skip to Main Content

I have a problem with @if in the Angular template flow syntax.

A value is available in an RxJs Observable. So the async pipe helps and the value is assigned to a variable.

@if (currentPageNumber$ | async; as currentPageNumber) {
// currentPageNumber is number

For value 0 the if statement is not valid. So I exclude only null values… but now the value of currentPageNumber is boolean.

@if ((currentPageNumber$ | async) !== null; as currentPageNumber) {
// currentPageNumber is boolean

How can I check against null but keep my variable with the value of the stream?

3

Answers


  1. Looks like a limitation of the @if syntax (0 evaluates to false in JS so you can’t use the syntax), you can just workaround it, by setting the value to string '0' but you need to take care of converting it back to number using +

    import { AsyncPipe } from '@angular/common';
    import { Component } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    import { of } from 'rxjs';
    import 'zone.js';
    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [AsyncPipe],
      template: `
        @if (check(currentPageNumber$ | async); as currentPageNumber) {
          {{+currentPageNumber}}
        }
      `,
    })
    export class App {
      name = 'Angular';
      currentPageNumber$ = of(0);
    
      check(value: any) {
        return value === 0 ? '0' : value;
      }
    }
    
    bootstrapApplication(App);
    

    Stackblitz Demo

    Login or Signup to reply.
  2. If you are not a fan of having nested if-s in the template you can use the following approach (like the approach shared by jeremy-denis).

    Here I’m modifying the response so that it is no longer a "falsy" value, so once the | async is evaluated to "truthy" value you will get the block below rendered and you can you the users reference to access the number.

    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [CommonModule],
      template: `
          <pre>{{str$ | async | json}}</pre>
          @if (str$ | async; as users) {
               {{users | json}}   
          }
      `,
    })
    export class App {
      str$ = of(0).pipe(
        /// the delay will result in `null` value for the first 2sec
        delay(2000),
        map((x) => {
          // mutate the response to something that is not null and store the value
          return  {
            pageSize: 0
          };
        })
      );
    }
    
    Login or Signup to reply.
  3. You can wrap the value directly in the template, this is probably the most straight forward way knowing how the AsyncPipe works.

    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [AsyncPipe],
      template: `
        @if({value: (sub$ | async)}; as wrappedValue) {
          foo {{wrappedValue.value}}
        } @else {
          bar
        }
      `,
    })
    export class App {
      sub$ = new BehaviorSubject(0);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search