0
votes

I expect *ngFor to iterate through the results of http.get which is made available via async pipe. Items are not being rendered, neither is the loading div.

Service:

public getKeywords = () =>  {
   return this.http.get<getKeywords>(`${this.uri}/keywords`);
}

Interface:

interface getKeywords {
  keywords: Array<object>;
}

TS:

export class KeywordsSettingsComponent implements OnInit {

  public currentKeywords$: any;

  constructor(private profileProvider: ProfileProvider) { }

  ngOnInit() {
    this.currentKeywords$ =
      this.profileProvider.getKeywords().pipe(map(({ keywords }) => keywords));
  }
}

Template:

<div class="row">
  <ng-template *ngIf="currentKeywords$ | async as currentKeywords ; else loading">
    <div class="keyword" * ngFor="let keywordObj of currentKeywords">
      {{ keywordObj.keyword }}
      <span class="icon-close"> </span>
    </div>
  </ng-template>
  <ng-template #loading> Loading keywords...</ng-template>
</div>

The fact that the loading div is not displaying is indicated that a value isn't being emitted. If I subscribe in the ngOnInt like so:

 this.currentKeywords$ = this.profileProvider.getKeywords().pipe(map(({keywords}) => keywords), share()).subscribe(res => res));

The loading div does show, but the result is not rendered in the *ngFor div. However I understand async pipe manages the subscriptions/unsubscribe, so subscribing in the ngOnInit should be unnecessary.


Result from http.get: The HTTP call returns an object which has several properties, one of which is "keywords" which contains an array of objects. I am using map() in order to map to a single property and access the array of objects.

{..."keywords":[{"id":331,"keyword":"spam"},{"id":330,"keyword":"foo"},{"id":332,"keyword":"brexit"}]}
1
I'd check in dev tools too see what your HTTP call is returning. You might be expecting an array while the return may be just an object. - Uğur Dinç
The HTTP call is returning an object with a property "keywords" which is an array of objects. - Will

1 Answers

0
votes

Based on the fact that the HTTP is returning an object, you will need to change this:

<div class="keyword" * ngFor="let keywordObj of currentKeywords">

to this:

<div class="keyword" *ngFor="let keywordObj of currentKeywords.keywords">

and I'd also change this:

this.currentKeywords$ =
      this.profileProvider.getKeywords().pipe(map(({ keywords }) => keywords));

to this as well:

this.currentKeywords$ = this.profileProvider.getKeywords();

...since that map is not really mapping anything.

You may also need to change your first <ng-template to e.g <div , as I imagine that it won't get rendered on its own.

Hope it helps.