0

We have 2 arrays Speisekarte and Essensplan - I want to call the method printName, to print out the name, I get from the ID.

The problem is, "name" is always undefined.

"ERROR TypeError: Cannot read property 'name' of undefined"

How can i fix async in methods in templates?

Template (Async in printName(essenName) )

<div *ngFor="let i of essensplan"> <br />
  <div><b>Woche : {{i.id}}</b></div> <br />
  <button *ngFor="let id of i.essenProWoche" (click)="print(id)">Gericht 
** {{printName(id)}} ** </button> 

Component

ngOnInit() {
  console.log("ngOnInite essensplan.component")
  this.getSpeisekarte();
  this.getEssensplan();

}

printName(id: number) {
  this.essenName = this.speisekarte.find(i => i.id == id ).name

 getSpeisekarte(): void {
  this.essenService.getSpeisekarte()
  .subscribe(speisekarte => this.speisekarte = speisekarte);
}

getEssensplan(): void {
  this.essensplanService.getEssensplan()
    .subscribe(essensplan => this.essensplan = essensplan)

}
2
  • 1
    In your template essenName is not defined. do you mean {{printName(id)}} ? Commented Sep 11, 2018 at 19:19
  • oh yes, sorry. Will edit it. Commented Sep 11, 2018 at 19:21

3 Answers 3

1

I'm not sure if it is possible to delay the entire component until both HTTP calls have completed. Instead of that, you can modify printName to handle the case where this.speisekarte hasn't been loaded yet. Then, tell the component to reload once it has.

Component

constructor(private changeDetector: ChangeDetectorRef) {}

ngOnInit() {
  console.log("ngOnInite essensplan.component")
  this.getSpeisekarte();
  this.getEssensplan();
}

printName(id: number) {
  const match = this.speisekarte.find(i => i.id == id );
  return match ? match.name : "";
}

getSpeisekarte(): void {
  this.essenService.getSpeisekarte()
  .subscribe(speisekarte => {
    this.speisekarte = speisekarte;
    this.changeDetector.markForCheck();
  });
}

getEssensplan(): void {
  this.essensplanService.getEssensplan()
  .subscribe(essensplan => { 
    this.essensplan = essensplan;
    this.changeDetector.markForCheck();
  });
}

Now, regardless of the order the HTTP requests complete, the templates will not error (although the names will be blank if getEssensplan finishes before getSpeisekarte


Note: I changed printName to return a value, since that will be necessary to display it

Sign up to request clarification or add additional context in comments.

1 Comment

YOU'RE A LEGEND. THANKS!
0

You can use AsyncPipe "The async pipe subscribes to an Observable or Promise and returns the latest value it has emitted. When a new value is emitted, the async pipe marks the component to be checked for changes. When the component gets destroyed, the async pipe unsubscribes automatically to avoid potential memory leaks."

<div *ngFor="let i of essensplan | async "> <br />

or use NgIF operator to show safely the view.

Please check the Answer for the same problem.

Comments

0

Use Observables for your problem. They will significantly reduce and improve your code. Angular has a buildin pipe called async-pipe which subscribes as long as the component is alive.

export class MyEssenComponent {
  essensPlan$: Observable<Essensplan>;
  speisekarte$: Observable<Speisekarte>;

  ngOnInit(): void {
    this.essensPlan$ = this.essensplanService.getEssensplan();
    this.speisekarte$ = this.essenService.getSpeisekarte();
  }

  get name(id: string): Observable<string> {
    return this.speisekarte$.pipe(
      filter(speisekarte => speisekarte.id === id),
      map(speisekarten => speisekarten[0] ? speisekarten[0].name : '')
    );
  }
}

Then you can easily rewrite your template to

<div *ngFor="let i of essensplan$ | async"> <br />
  <div><b>Woche : {{i.id}}</b></div> <br />
  <button *ngFor="let id of i.essenProWoche" (click)="print(id)">
    Gericht ** {{name(id) | async}} **
  </button>
</div>

Also I recommend to choose more meaningful variable names as the are totally irritating. E.g. you chose essenProWoche attribute for an array of IDs, or just i as variable.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.