Miguel Moura
Miguel Moura

Reputation: 39374

Check if variable is undefined with *ngIf

I have the following on an Angular 7 application:

<ng-container *ngIf="(post$ | async) as post; else loader">
  <div *ngIf="post; else empty">
    Post content
  </div>
</ng-container>
<ng-template #empty>
  Post not found
</ng-template>
<ng-template #loader>
  Loading post
</ng-template>

This works fine when post is defined ...

However when post is undefined the "Post not Found" does not show ...

... I just see the Loading message which does not disappears.

What am I missing?

Update

post$ is defined as follows in the component:

Note: post$ is not an array. See envelope.result[0] in the code.

export class PostDetailComponent implements OnInit {

  @Input() postId: number;

  post$: Observable<PostDetailModel>;

  constructor(private postService: PostService) { }

  ngOnInit() {

    this.post$ = this.getPost();

  }

  getPost(): Observable<PostDetailModel> {

    return this.postService.getByPostId(this.postId).pipe(

      map((envelope: Envelope<GetByPostIdResponse>) => envelope.result[0]),

      map((response: GetByPostIdResponse) => {

        return response == null ? null : {
          id: response.id,
          title: response.title
          // other properties
        };

      }));

  }

Upvotes: 0

Views: 5877

Answers (3)

Igor
Igor

Reputation: 62213

post is evaluated as truthy/falsy already in the initial ng-container. If post resolves to undefined then the ng-template #loader will display. Your current logic will never display ng-template #empty. I would recommend you use map to change the returned value if it is undefined and then check that in your subsequent *ngIf.

stackblitz

component

export class AppComponent implements OnInit {
  post$: Observable<any>;

  ngOnInit(){
    this.post$ = of(undefined).pipe(
      delay(2000),
      map(_ => typeof _ === 'undefined' ? 'NotFound' : _)
    );
  }
}

template

<ng-container *ngIf="(post$ | async) as post; else loader">
  <div *ngIf="post !== 'NotFound'; else empty">
    Post content
  </div>
</ng-container>
<ng-template #empty>
  Post not found
</ng-template>
<ng-template #loader>
  Loading post
</ng-template>

Upvotes: 3

bgraham
bgraham

Reputation: 1997

I think its always undefined. Undefined while its waiting, and also undefined or maybe null when it returns in that state. I think the best way to to be more explicit about whats going on:

ts

loading = false;
post;

getPost() {
   this.loading = true;
   this.postService.getPost().subscribe(post => {
      this.loading = false;
      this.post = post;
   });
}

html

<ng-container *ngIf="!loading; else loader">
  <div *ngIf="post; else empty">
    Post content
  </div>
</ng-container>
<ng-template #empty>
  Post not found
</ng-template>
<ng-template #loader>
  Loading post
</ng-template>

this way you aren't trying to infer the state of the post from which kind of falsey it might be

Upvotes: 0

nircraft
nircraft

Reputation: 8478

you can use !! to check for valid values. You can see explanation of !! here

<ng-container *ngIf="(post$ | async) as post; else loader">
      <div *ngIf="!!post; else empty">
        Post content
      </div>
    </ng-container>
    <ng-template #empty>
      Post not found
    </ng-template>
    <ng-template #loader>
      Loading post
    </ng-template>

Upvotes: 1

Related Questions