1

Below is my partial angular2 component template html. "searchTickets$" is an Observable of array of objects.

<table class="table table-condensed" *ngIf="searchTickets$">
<thead>
    <tr>
        <th><h3>Ticket ID</h3></th>
    </tr>
</thead>
<tbody>
    <tr *ngFor="let ticket of searchTickets$  | async">
        <td><small>{{ticket.ticketID}}</small></td>     
    </tr>
</tbody>
</table>

My intention is that the table should be displayed only when the observable returns 1 or more records.

What needs to be modfied in *ngIf condition to make that happen.

refactor
  • 13,954
  • 24
  • 68
  • 103
  • nothing, try to initialize your searchTickets, remove ngIf, if array is empty nothing will be displayed, after search you set that array to responsed data, if response have something it will render that elements – dev_in_progress Nov 28 '16 at 10:35
  • 2
    did you try `*ngIf="(searchTickets$ | async).length"` ? – Poul Kruijt Nov 28 '16 at 10:38
  • @ PierreDuc , yes , it throws " Cannot read property 'length' of null" error. – refactor Nov 28 '16 at 10:40
  • Initially tit would be null , you'd need to safety check it first like this : *ngIf="(searchTickets$ | async)?.length" – Milad Nov 28 '16 at 10:43

2 Answers2

2

As @xe4me said :

<table class="table table-condensed" *ngIf="(searchTickets$ | async)?.length">

Should work.

BUT

Don't forget that async is subscribing to your observable.

Which means that having :

<table class="table table-condensed" *ngIf="searchTickets$">

and

<tr *ngFor="let ticket of searchTickets$  | async">

Will lead to two different subscriptions.

If you're making an HTTP call somewhere in your observable chain, it'll be fired twice.

This is not a really good option here I guess.

Instead, you should be doing something like that :


if you want to handle the observable from your HTML without firing your observable multiple times due to async

@Component({
  ...
})
export class YourComponent {
  public searchTickets: any;

  constructor(private yourService: any) {
    this.searchTickets = yourService
      .getSearchTicket()
      .share();

    // share allows you to avoid duplicate subscriptions
  }
}

if you want to handle the observable from your TS

@Component({
  ...
})
export class YourComponent implements OnDestroy {
  public searchTickets: any;
  private searchTicketsSub: Subscription;

  constructor(private yourService: any) {
    this.searchTickets =
      // let say you have the observable coming from a service that
      // makes an HTTP call 
      yourService
        .getSearchTicket()
        .subscribe((searchTickets: any) => this.searchTickets = searchTickets);
  }

  ngOnDestroy() {
    // then, don't forget to unsubscribe
    this.userSub.unsubscribe();
  }
}
maxime1992
  • 22,502
  • 10
  • 80
  • 121
0

You should try

<table class="table table-condensed" *ngIf="(searchTickets$ | async)?.length > 0">
Ankush Jain
  • 5,654
  • 4
  • 32
  • 57
  • 2
    searchTickets$ is an observable , you can't get it's length like this , you first need to subscribe to it ! – Milad Nov 28 '16 at 10:41
  • Wow that's hell of an edit. To take @xe4me code, you should just have removed your answer. – maxime1992 Nov 28 '16 at 10:47
  • I dint took @xe4me's code. My answer came from here http://stackoverflow.com/questions/38057537/how-to-check-length-of-the-an-observable-array#answer-38057574. – Ankush Jain Nov 28 '16 at 10:52
  • This definitely works, but the problem is you'd be subscribing to that source twice ! Which is not a big problem if the source is not gonna be emitting stuff too much , otherwise you'd need to tweek the source. – Milad Nov 28 '16 at 10:54
  • @xe4me I made an answer that doesn't fire twice ;) – maxime1992 Nov 28 '16 at 11:02