简体   繁体   中英

find of undefined in service method called from component Angular

I am calling a service method(findDebtorName) from a component oninit method which calls findDebtor method. this.debtors is subscribed and data reaches late. this.debtors.find in findDebtor method is called before data is in this.debtors due to which I am facing find of undefined error

Component file

ngOnInit(): void {
    this.documentService.currentDocument = null;
    this.filteredDocs = this.documents.map((doc) => {
      doc.company = this.debtorService.findDebtorName(doc.debtors[0]);
      return doc;
    });
    this.creditOverviewSortingService.onSortChange(this.sortDocuments.bind(this));
    this.filteredDocuments();
  }

service file

@Injectable()
export class DebtorService {

  customerGroup: Debtor;
  debtors: Debtor[];

  constructor(private sharedDataService: SharedDataService, private http: HttpClient) {
    this.sharedDataService.customerGroup.subscribe((customerGroup) => {
      this.customerGroup = new Debtor(customerGroup);
    });

    this.sharedDataService.debtors.subscribe((debtors) => {
      this.debtors = debtors;
    });
  }

  findDebtorName(debtorId: string): string {
    const correctDebtor = this.findDebtor(debtorId);
    return correctDebtor ? correctDebtor.name : 'DEBTOR NOT FOUND';
  }

  findDebtor(debtorId: string): Debtor {
      return this.debtors.find((debtor) => debtor.id === debtorId);
  }

}

Kindly let me know what I am doing wrong.

You could make sure that the async data this.customerGroup and this.debtors are defined before trying to access them. And since there are 2 async data involved the complete flow need to be async as well to make sure the data is initialized before processing them.

Service

@Injectable()
export class DebtorService {
  customerGroup: Debtor;
  debtors: Debtor[];

  constructor(private sharedDataService: SharedDataService, private http: HttpClient) { }

  initializeData(): Observable<any> {
    return combineLatest([this.sharedDataService.customerGroup, this.sharedDataService.debtors]).pipe(
      take(1),
      tap(response => {
        this.customerGroup = response[0];
        this.debtors = response[1];
      }),
      catchError(error => {
        // handle error
        return of(error);
      })
    );
  }

  findDebtorName(debtorId: string): string {
    return this.findDebtor(debtorId).pipe(
      map(correctDebtor => {
        return correctDebtor ? correctDebtor.name : 'DEBTOR NOT FOUND';
      })
    );
  }

  findDebtor(debtorId: string): Debtor {
    return this.initializeData().pipe(
      map(response => {
        return this.debtors.find((debtor) => debtor.id === debtorId);
      })
    );
  }
}

Component

ngOnInit(): void {
  this.documentService.currentDocument = null;
  forkJoin(this.documents.map((doc) => this.debtorService.findDebtorName(doc.debtors[0]))).subscribe(
    response => {
      this.documents.forEach(doc, index => {
        doc.company = response[index];
      });
    }
  );
  this.creditOverviewSortingService.onSortChange(this.sortDocuments.bind(this));
  this.filteredDocuments();
}

Note that the this.documents is also modified asynchronously in the ngOnInit of the component.

You should make sure the data loaded before call findDebtorName().

@Injectable()
export class DebtorService {
  customerGroup: Debtor;
  debtors: Debtor[];

  constructor(
    private sharedDataService: SharedDataService,
    private http: HttpClient,
  ) {}

  async loadData() {
    // get data parallelly
    const data = await Promise.all([
        this.sharedDataService.customerGroup.toPromise,
        this.sharedDataService.debtors.toPromise,
    ])

    const customerGroup = new Debtor(data[0]) ;
    const debtors = data[1];
  }

  findDebtorName(debtorId: string): string {
    const correctDebtor = this.findDebtor(debtorId);
    return correctDebtor ? correctDebtor.name : 'DEBTOR NOT FOUND';
  }

  findDebtor(debtorId: string): Debtor {
    return this.debtors.find(debtor => debtor.id === debtorId);
  }
}



async ngOnInit(): Promise<void> {
    // load data before call any function which depends on this data
    await this.debtorService.loadData();

    this.documentService.currentDocument = null;
    this.filteredDocs = this.documents.map((doc) => {
      doc.company = this.debtorService.findDebtorName(doc.debtors[0]);
      return doc;
    });
    this.creditOverviewSortingService.onSortChange(this.sortDocuments.bind(this));
    this.filteredDocuments();
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM