简体   繁体   English

如何将可观察值传递给@Input() Angular 4

[英]How to pass observable value to @Input() Angular 4

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.我是getAnswers():Observable<AnswerBase<any>[]> ,我遇到以下情况,即我有一个服务getAnswers():Observable<AnswerBase<any>[]>和两个相互关联的组件。

  • 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 . online-quote组件在其ngOnInit()方法中调用服务getAnswers():Observable<AnswerBase<any>[]>并将其结果传递给组件dynamic-form

To illustrate the situation this is the code of my two components:为了说明这种情况,这是我的两个组件的代码:

online-quote.component.html:在线-quote.component.html:

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

online-quote.component.ts:在线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:动态form.component.html:

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

dynamic-form.component.ts:动态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.我的问题是,如果服务getAnswers():Observable<AnswerBase<any>[]>的结果信息是getAnswers():Observable<AnswerBase<any>[]>那么将信息从在线报价传递到动态表单的正确方法是什么。

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!非常感谢你!

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 .假设DynamicFormService.getAnswers('CAR00PR')异步的(可能是),使用async Pipe传递异步结果是正确的方式,但是您不能期望在创建DynamicFormComponent时立即获得异步结果(在 ngOnInit 处),因为异步的 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. 1. 在ngOnChanges lifehook 听@Input() answers valueChange @Input() answers

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. 2. 将 Observable 直接传递给DynamicFormComponent并订阅它以收听它的结果。

online-quote.component.html:在线报价.component.html:

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

dynamic-form.component.ts:动态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.我有一个与 OP 几乎相同的用例,并且提议的解决方案也适用于我。

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.我之前在模板中应用了异步管道作为 *ngIf 结构指令的一部分,并使用变量将已经评估的值传递给子组件。

<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 following Reason This is from the doc:我的方法和建议是将 BehaviorSubject 用于以下原因这是来自文档:

One of the variants of Subjects is the BehaviorSubject, which has a notion of "the current value". Subjects 的变体之一是 BehaviorSubject,它具有“当前值”的概念。 It stores the latest value emitted to its consumers, and whenever a new Observer subscribes, it will immediately receive the "current value" from the BehaviorSubject.它存储发送给其消费者的最新值,每当有新的观察者订阅时,它将立即从 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.我认为 OP 声明的子组件总是需要发出的最后一个值,因此我觉得 BehaviorSubject 更适合于此。

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,在 html 视图中,

<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 subscribed dynamic-form.component.ts订阅答案的方式没有变化 dynamic-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);
    })
}

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 .我遇到了同样的问题,我创建了一个提供ObservableInput装饰器的小型库来帮助解决这个问题: https : //www.npmjs.com/package/ngx-observable-input Example code for that case would be:这种情况的示例代码是:

online-quote.component.html:在线报价.component.html:

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

dynamic-form.component.ts:动态form.component.ts:

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

  ...
}

将可观察对象传递给输入是要避免的,原因是:当检测到新输入时,您如何处理对前一个可观察对象的订阅?让我们澄清一下,可以订阅 observable,一旦您订阅,您有责任完成 observable 或取消订阅。一般来说,这甚至被认为是一种反模式,将 observables 传递给不是运算符的函数,因为您正在执行命令式编码,其中 observables 应该以声明方式使用,将一个传递给组件也不例外。

如果你真的想这样做,你需要非常小心,不要忘记取消订阅 observable。为此,您要么必须确保输入永远不会更改,要么专门完成对覆盖输入的任何先前订阅(嗯......就在它被覆盖之前)

如果你不这样做,你最终可能会出现泄漏,并且很难找到错误。因此,我会推荐以下 2 种替代方案:

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.我对angular不getAnswers():Observable<AnswerBase<any>[]>以下情况,这是我有一个服务getAnswers():Observable<AnswerBase<any>[]>和两个彼此相关的组件。

  • 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 .在线报价组件在其ngOnInit()方法中调用服务getAnswers():Observable<AnswerBase<any>[]> ,并将其结果传递给组件dynamic-form

To illustrate the situation this is the code of my two components:为了说明这种情况,这是我的两个组件的代码:

online-quote.component.html: online-quote.component.html:

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

online-quote.component.ts: 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: dynamic-form.component.html:

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

dynamic-form.component.ts: 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.我的问题是,如果服务getAnswers():Observable<AnswerBase<any>[]>的结果信息是getAnswers():Observable<AnswerBase<any>[]>那么将信息从在线报价传递给动态形式的正确方法是什么。

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!非常感谢你!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM