How to pass observable value to @Input() Angular 4 How to pass observable value to @Input() Angular 4 angular angular

How to pass observable value to @Input() Angular 4


Assume DynamicFormService.getAnswers('CAR00PR') is asynchronous(probably it is), using async Pipe to pass asynchronous result is on the right way, but you cannot expect to get the asynchronous result right now when DynamicFormComponent is created(at ngOnInit) because of Asynchonous. The result isn't ready yet when running your below line of code.

this.form = this.qcs.toFormGroup(this.answers);

There are several ways that can fix your problem.

1. listen to valueChange of @Input() answers at ngOnChanges lifehook.

ngOnChanges(changes) {  if (changes.answers) {    // deal with asynchronous Observable result    this.form = this.qcs.toFormGroup(changes.answers.currentValue);  }}

2. pass Observable directly into DynamicFormComponent and subscribe to it to listen to it's result.

online-quote.component.html:

<app-dynamic-form [answers]="answers$"></app-dynamic-form>

dynamic-form.component.ts:

@Component({  ...})export class DynamicFormComponent implements OnInit {  @Input() answers: Observable<AnswerBase[]>;  ngOnInit() {    this.answers.subscribe(val => {      // deal with asynchronous Observable result      this.form = this.qcs.toFormGroup(this.answers);    })}


I had an almost identical use-case as OP and the proposed solution worked for me too.

For simplicity sake, I figured out a different solution that worked in my case and seems a little simpler. I applied the async pipe earlier on in the template as part of the *ngIf structural directive and used variables to be able to pass through the already evaluated value through to the child component.

<div *ngIf="answers$ | async as answers">    <app-dynamic-form [answers]="answers"></app-dynamic-form></div>


My appraoch and suggestion is to use BehaviorSubject for the followingReasonThis is from the doc:

One of the variants of Subjects is the BehaviorSubject, which has anotion of "the current value". It stores the latest value emitted toits consumers, and whenever a new Observer subscribes, it willimmediately receive the "current value" from the BehaviorSubject.

I presume that the child component that the OP has declared would always need the last value emitted and hence I feel BehaviorSubject would be more suited to this.

Online-quote.component

@Component({  selector: 'app-online-quote',  templateUrl: './online-quote.component.html',  styleUrls: ['./online-quote.component.css'],  providers:  [DynamicFormService]})export class OnlineQuoteComponent implements OnInit {  public answers$: BehaviorSubject<any>;  constructor(private service: DynamicFormService) {       this.answers$ = new BehaviorSubject<any>(null);   }  ngOnInit() {        this.service.getAnswers("CAR00PR").subscribe(data => {            this.answer$.next(data); // this makes sure that last stored value is always emitted;         });  }}

In the html view,

<app-dynamic-form [answers]="answer$.asObservable()"></app-dynamic-form>

// this emits the subject as observable

Now you can subscribe the values in the child component. There is no change in how the answer is to be subscribeddynamic-form.component.ts

@Component({  ...})export class DynamicFormComponent implements OnInit {  @Input() answers: Observable<any>;  ngOnInit() {    this.answers.subscribe(val => {      // deal with asynchronous Observable result      this.form = this.qcs.toFormGroup(this.answers);    })}