Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

async pipe sends 'null' value to the child component

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.

like image 407
Sh eldeeb Avatar asked May 08 '20 14:05

Sh eldeeb


3 Answers

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.

like image 126
HTN Avatar answered Oct 20 '22 14:10

HTN


app.component.html

<ng-container *ngIf=(test$ | async) as test; else defaultTmpl>
    <child [test]="test"></child>
</ng-container>
<ng-template #defaultTmpl>Default Template<ng-template>

For more details please take a look: https://ultimatecourses.com/blog/angular-ngif-async-pipe

like image 40
Alexander Avatar answered Oct 20 '22 14:10

Alexander


Much easier solution:

(test$ | async) || defaultTestValue
like image 21
rob2d Avatar answered Oct 20 '22 15:10

rob2d