You can't have *ngFor
and *ngIf
on the same element, so you can use ng-container
to prevent the additional div
wrapper being included in the output:
<ng-container *ngIf="(observable$ | async).length; else noContent">
<div *ngFor="let result of (observable$ | async)">
<h3>{{ result.name }}</h3>
<p>{{ result.price | currency }}</p>
</div>
</ng-container>
<!-- optional -->
<ng-template #noContent>
Nothing to show.
</ng-template>
import { Component, OnInit } from "@angular/core";
import { of, Observable } from "rxjs";
import { map, filter, tap } from "rxjs/operators";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
observable$: Observable<{name: string, price: number}[]>;
ngOnInit() {
// To simulate requests with some/no results
// Change to 1 to always return data, 0 for empty results.
const chance = Math.random();
this.observable$ = this.getMockData(chance).pipe(
map(res => res.results)
);
}
getMockData(random) {
const results =
random <= 0.5
? { results: [] }
: {
results: [
{ name: "Widget", price: 300 },
{ name: "Widget 2", price: 50 },
{ name: "Widget 3", price: 75 }
]
};
return of(results);
}
}
Output:
<div _ngcontent-sqx-c0="">
<h3 _ngcontent-sqx-c0="">Widget</h3>
<p _ngcontent-sqx-c0="">$300.00</p>
</div>
<div _ngcontent-sqx-c0="">
<h3 _ngcontent-sqx-c0="">Widget 2</h3>
<p _ngcontent-sqx-c0="">$50.00</p>
</div>
<div _ngcontent-sqx-c0="">
<h3 _ngcontent-sqx-c0="">Widget 3</h3>
<p _ngcontent-sqx-c0="">$75.00</p>
</div>
Stackblitz