首页 > 解决方案 > ANGULAR - 服务尚未完成加载 Observable在被方法使用之前

问题描述

所以我得到了我的 HomeComponent,它使用 MatTableDataSourceopenFaultsSource$获取其数据形式,Observable<IFault[]>以将数据显示为表格。

ngOnInit() {
    this.dataProviderService.openFaults$.subscribe(faults => this.openFaultsSource$.data = faults);
    this.dataProviderService.closedFaults$.subscribe(faults => this.closedFaultsSource$.data = faults);
  }
IFault {
 deviceId: number,
 locationId: number,
 ...,
}

我不需要显示 ID,而是显示从其他 Observable 获得的连接名称。例如:

IDevice {
 deviceId: number,
 deviceName: string,
 ...,
}

所以我的 HomeComponent.html 看起来像这样:

<table mat-table [dataSource]="openFaultsSource$" class="mat-Table mat-elevation-z8">

              <ng-container matColumnDef="deviceName">
                <th mat-header-cell *matHeaderCellDef> Gerätenummer </th>
                <td mat-cell *matCellDef="let element"> {{getDeviceNameById(element.deviceId) | async}} </td>
              </ng-container>

              <ng-container matColumnDef="locationName">
                <th mat-header-cell *matHeaderCellDef> Örtlichkeit </th>
                <td mat-cell *matCellDef="let element"> {{element.locationId}} </td>
              </ng-container>

              <ng-container matColumnDef="creationDate">
                <th mat-header-cell *matHeaderCellDef> Erstellungsdatum </th>
                <td mat-cell *matCellDef="let element"> {{element.creationDate}}  </td>
              </ng-container>

              <ng-container matColumnDef="componentName">
                <th mat-header-cell *matHeaderCellDef> betroffenes Bauteil </th>
                <td mat-cell *matCellDef="let element"> {{element.componentName}}</td>
                <td><button mat-button>test</button></td>
              </ng-container>

              <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
              <tr mat-row *matRowDef="let row; columns: displayedColumns" class="table-row" (click) = "openFaultDialog(row)"></tr> 

            </table>

在 component.ts 中:

getDeviceNameById(id: number): Observable<string> {
    return this.dataProviderService.getDeviceNameById(id);
  }

我的 dataProviderService 使用所有其他服务,处理逻辑并将数据传递给组件。它看起来像这样:

@Injectable({
  providedIn: 'root'
})
export class DataProviderService {

  openFaults$: Observable<IFault[]>;
  closedFaults$: Observable<IFault[]>;

  constructor(private faultLogicService: FaultLogicService,
              private deviceLogicService: DeviceLogicService,
              private locationLogicService: LocationLogicService,
              private componentLogicService: ComponentLogicService,
              private deviceTypeLogicService: DeviceTypeLogicService,
              private faultTypeLogicService: FaultTypeLogicService,
              private solveTypeLogicService: SolveTypeLogicService) {
    this.openFaults$ = this.faultLogicService.openFaults$;
    this.closedFaults$ = this.faultLogicService.closedFaults$;
  }

  getComponentsByDeviceName(device: any): any {
    throw new Error("Method not implemented.");
  }
  getDevicesByLocationInput(inputString: any): any {
    throw new Error("Method not implemented.");
  }

  getDeviceNameById(id: number): Observable<string> {
    return this.deviceLogicService.getNameById(id);
  }

}

现在 deviceLogicService:

@Injectable({
  providedIn: 'root'
})
export class DeviceLogicService {

  deviceSubject = new BehaviorSubject<IDevice[]>([]);
  devices$ = this.deviceSubject.asObservable();

  constructor(private deviceService: DeviceService) {
  EDIT 1: // this.init(); // init() is called in app.component when calling the 
                          // page for the first time 
  }

  init() {
    this.deviceService.getDevices()
    .pipe(tap(console.log))
    .subscribe(devices => {
      this.sortDevices(devices);
      this.deviceSubject.next(devices);
    });
  }

  sortDevices(devices: IDevice[]) {
    devices.sort((a, b) => a.name.localeCompare(b.name));
  }

  getNameById(deviceId: number): Observable<string> {
    return this.devices$.pipe(map(devices => devices.find(device => device.id === deviceId).name));
  }
}

由 deviceLogicService 用来填充其 BS 的 deviceService:

@Injectable({
  providedIn: 'root'
})
export class DeviceService {

  private accessPointUrl = 'https://localhost:44360/api/Devices/';

  constructor(private http: HttpClient) { }

  getDevices(): Observable<IDevice[]> {
    return this.http.get<IDevice[]>(this.accessPointUrl);
  }
}

[问题] 基本上它正在工作,它正在将正确的名称加载到所选的 id,但问题是我收到错误ERROR TypeError: Cannot read property 'name' of undefined at MapSubscriber.project (device-logic.service.ts:77),因为它在服务完成加载所有设备之前调用该方法。

[问题]

有没有办法告诉方法等到所有设备都加载完毕?我的代码结构是否正常,还是很复杂?有没有更简单的方法来获得相同的结果?

我对 Angular 还很陌生,只是不知道如何解决这个问题。我在这里先向您的帮助表示感谢。

标签: angulartypescriptservicerxjsmat-table

解决方案


推荐阅读