async pipe sends 'null' value to the child component

Sh eldeeb picture Sh eldeeb · May 8, 2020 · Viewed 9.3k times · Source

I want to pass a value to the child component. this value is an Observable, so I use async pipe.

<child [test]="test$ | async"></child>

test$ is just a normal observable variable, that emits values after a period of time (3000 ms), simulating an API request to the server.

this.test$=timer(3000).pipe(
      mapTo("value")      
 )

in child component, I just want to check test value

@Input() test: any;

constructor(){
    console.log("child/test", this.test); //null
    setTimeout(()=>console.log("child/test (timeout)", this.test),4000) //value

   if(this.test){
     //maintain and check `this.test`
     //this code will not run, because at this point `this.test` is null.
     //we don't know the exact time that `this.test` will have a value
     //this causes that `this.test` is wrong

      this.checked=true 
     }
  }

<div *ngIf="checked">{{test}}</div>

I don't want to change the type of test to be Observable and subscribe to it. I want to receive the final value directly. and I don't want to modify the edit component at all.

using ChangeDetectorRef to manually trigger the change detector is not

@Input() test$:Observable

constructor(){
  this.test$.subscribe(v=>this.test=v)
}

I also made this stackblitz to check the value changing among all the compoonent's hooks.

Answer

HTN picture HTN · May 8, 2020

async pipe will return null when no value is emitted by Observable yet. So, the value of test in child component is:

  • undefined in constructor because @Input() variables are not assigned at this state
  • null after that (e.g. first onChanges hook or onInit hook`) when no value is emitted by the Observable
  • value when the Observable emit new value

Now, you should either create child component only when test variable is not null with *ngIf, or handle correctly the state of child component with nullable test (e.g. Add a progress bar when test is null). The choice is up to you.