鍍金池/ 問答/HTML5  網絡安全  HTML/ Angular 6如何異步更新列表信息?

Angular 6如何異步更新列表信息?

本人前端萌新,學習過一點點Angular,然后自己寫了一個簡單例子,就是顯示一下瀏覽器信息,相關代碼如下,可以正常運行,界面會先顯示瀏覽器的信息,然后過幾秒顯示出IP地址。

import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import platform from 'platform';
import 'rxjs/add/operator/toPromise';

@Injectable()
export class ClientInfoService {
  private static ipUrl = 'http://httpbin.org/ip';

  constructor(private httpClient: HttpClient) {

  }

  getClientInfo(): Promise<ClientInfo[]> {
    return new Promise((resolve, reject) => {
      const clientInfo: ClientInfo[] = [];
      clientInfo.push({key: '操作系統', value: `${platform.os}`});
      clientInfo.push({key: '瀏覽器', value: `${platform.name} ${platform.version}`});
      clientInfo.push({key: '用戶代理', value: platform.ua});
      this.httpClient.get(ClientInfoService.ipUrl)
        .subscribe(data => {
          clientInfo.push({key: 'IP地址', value: data['origin']});
          resolve(clientInfo);
        }, err => {
          reject(err);
        });
    });
  }
}

export interface ClientInfo {
  key: string;
  value: string;
}

然后Angular更新到6了,我研究一段時間以后,嘗試升級了一下,好不容易代碼能運行了,但是這下IP地址無法更新了。代碼現在如下,程序其他部分也作了相應修改,可以編譯。但是現在程序可以顯示瀏覽器的信息,IP地址永遠為空。我想了想,感覺問題應該是出在rxjs這里,因為我對這些概念不太理解,代碼肯定寫錯了,所以希望高手們給我解解惑。感謝各位!

@Injectable()
export class ClientInfoService {
  private static ipUrl = 'http://httpbin.org/ip';

  constructor(private httpClient: HttpClient) {

  }

  getClientInfo(): Observable<ClientInfo[]> {
    const clientInfo: ClientInfo[] = [];
    clientInfo.push({key: '操作系統', value: `${platform.os}`});
    clientInfo.push({key: '瀏覽器', value: `${platform.name} ${platform.version}`});
    clientInfo.push({key: '用戶代理', value: platform.ua});
    const data = this.httpClient.get(ClientInfoService.ipUrl)
      .pipe(
        catchError(this.handleError('獲取IP地址', '網絡錯誤'))
      );
    clientInfo.push({key: 'IP地址', value: data['origin']});
    return of(clientInfo);
  }

  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
      console.error(error);
      return of(result as T);
    };
  }
}

export interface ClientInfo {
  key: string;
  value: string;
}

感謝各位的解答,現在終于可以顯示IP地址了,但是還有一個問題就是原來是立即顯示一些東西,然后獲取到IP地址之后才更新?,F在我這個代碼變成了需要等到IP地址拿到之后才整個顯示數據。請問這下應該如何處理?

  getClientInfo(): Observable<ClientInfo[]> {
    const clientInfo: ClientInfo[] = [];
    clientInfo.push({key: '操作系統', value: `${platform.os}`});
    clientInfo.push({key: '瀏覽器', value: `${platform.name} ${platform.version}`});
    clientInfo.push({key: '用戶代理', value: platform.ua});
    return this.httpClient.get(ClientInfoService.ipUrl)
      .pipe(
        map(data => data['origin']),
        catchError(this.handleError('獲取IP地址', '網絡錯誤')),
        map(e => {
          clientInfo.push({key: 'IP地址', value: e});
          return clientInfo;
        })
      );
  }

感覺我描述的不夠清晰,順便補上視圖顯示的代碼。

@Component({
  template: `
    <mat-table #table [dataSource]="dataSource">
      <ng-container matColumnDef="key">
        <mat-header-cell *matHeaderCellDef>項目</mat-header-cell>
        <mat-cell *matCellDef="let row"> {{row.key}}</mat-cell>
      </ng-container>
      <ng-container matColumnDef="value">
        <mat-header-cell *matHeaderCellDef>值</mat-header-cell>
        <mat-cell *matCellDef="let row"> {{row.value}}</mat-cell>
      </ng-container>
      <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
      <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
    </mat-table>
  `,
})
export class ClientInfoComponent implements OnInit {
  dataSource: ClientInfoDataSource;
  displayedColumns = ['key', 'value'];

  constructor(private clientInfoService: ClientInfoService) {
  }


  ngOnInit(): void {
    this.dataSource = new ClientInfoDataSource(this.clientInfoService);
  }
}

class ClientInfoDataSource implements DataSource<any> {
  constructor(private clientInfoService: ClientInfoService) {
  }

  connect(): Observable<ClientInfo[]> {
    return this.clientInfoService.getClientInfo();
  }

  disconnect(): void {
  }

}
回答
編輯回答
忠妾

rxjs 需要訂閱,而上面這段代碼中 this.httpClient.get并未subscribe,也就不會觸發(fā),或者即使訂閱了也因為是異步執(zhí)行而沒有效果,最終直接返回了值為clientInfo的observer,這個值始終都會是[]
正確做法getClientInfo()應該返回代碼中定義的data這個Observable,比如說:

getClientInfo(): Observable<ClientInfo[]> {
    ...
    const data = this.httpClient.get(ClientInfoService.ipUrl)
      .pipe(
        map((rs) => [{key: 'IP地址', value: rs['origin']}]),
        catchError(this.handleError('獲取IP地址', '網絡錯誤'))
      );
    return data;
  }
2017年2月28日 04:36
編輯回答
喜歡你

好好看官方文檔老鐵

getConfig() {
  return this.http.get(this.configUrl);
}

showConfig() {
     this.configService.getConfig()
    .subscribe((data: Config) => this.config = {
        heroesUrl: data['heroesUrl'],
        textfile:  data['textfile']
    });
}
2018年2月3日 00:05