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

2020-08-09 05:16发布

I am new to angular and I have the following situation which is I have a service getAnswers():Observable<AnswerBase<any>[]>and two components that are related to each other.

  • online-quote
  • dynamic-form

online-quote component calls the service getAnswers():Observable<AnswerBase<any>[]> in its ngOnInit() method and the result of this, is passed to the component dynamic-form.

To illustrate the situation this is the code of my two components:

online-quote.component.html:

 <div>
    <app-dynamic-form [answers]="(answers$ | async)"></app-dynamic-form>
</div>

online-quote.component.ts:

@Component({
  selector: 'app-online-quote',
  templateUrl: './online-quote.component.html',
  styleUrls: ['./online-quote.component.css'],
  providers:  [DynamicFormService]
})
export class OnlineQuoteComponent implements OnInit {

  public answers$: Observable<any[]>;

  constructor(private service: DynamicFormService) {

   }

  ngOnInit() {
    this.answers$=this.service.getAnswers("CAR00PR");
  }

}

dynamic-form.component.html:

<div *ngFor="let answer of answers">
 <app-question *ngIf="actualPage===1" [answer]="answer"></app-question>
</div>

dynamic-form.component.ts:

@Component({
  selector: 'app-dynamic-form',
  templateUrl: './dynamic-form.component.html',
  styleUrls: ['./dynamic-form.component.css'],
  providers: [ AnswerControlService ]
})
export class DynamicFormComponent implements OnInit {
  @Input() answers: AnswerBase<any>[];

  constructor(private qcs: AnswerControlService, private service: DynamicFormService) {  }

  ngOnInit() {

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

  }

My question is what is the correct way to pass the information from online-quote to dynamic-form if the result information of the service getAnswers():Observable<AnswerBase<any>[]> is a observable.

I've tried it in many ways but it does not work. I would like someone to help me with this. Thank you very much!

4条回答
趁早两清
2楼-- · 2020-08-09 05:49

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);
    })
}
查看更多
放我归山
3楼-- · 2020-08-09 05:55

Modify the online-quote.component.ts to the following:

@Component({
    selector: 'app-online-quote',
    templateUrl: './online-quote.component.html',
    styleUrls: ['./online-quote.component.css'],
    providers:  [DynamicFormService]
})
export class OnlineQuoteComponent implements OnInit {

  public answers$: AnswerBase<any>[];

  constructor(private service: DynamicFormService) {}

  ngOnInit() {
    this.service.getAnswers("CAR00PR").subscribe(success => {
        this.answers$ = success;
    });
  }
}
查看更多
forever°为你锁心
4楼-- · 2020-08-09 05:57

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>
查看更多
▲ chillily
5楼-- · 2020-08-09 06:15

I had the same issue and I've created a small library that provides ObservableInput decorator to help with that: https://www.npmjs.com/package/ngx-observable-input. Example code for that case would be:

online-quote.component.html:

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

dynamic-form.component.ts:

@Component({
  ...
})
export class DynamicFormComponent implements OnInit {
  @ObservableInput() Input("answers") answers$: Observable<string[]>;

  ...
}
查看更多
登录 后发表回答