将数据从服务传递到组件 -->子组件 [英] Passing data from service to Component --> Child Components

查看:23
本文介绍了将数据从服务传递到组件 -->子组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简而言之,我正在使用这个 Plunker我有一个场景,我必须通过从服务中读取元素数据来动态创建控件.因此,当我从服务中读取数据时,它是异步的.但是我必须根据从服务接收到的数据创建一些具体对象并将其传递给子组件.所以这是我的逻辑

主要组件的Html如下.

 <app-dynamic-form [问题]="问题"></app-dynamic-form></离子含量>

主要组件的类如下

Class ComponentMain{@Input() 问题: QuestionBase[]=[];构造函数(公共导航控件:导航控制器,公共导航参数:导航参数,私有 qcs:服务){qcs.getQuestions(this.parameter1.$key).subscribe(result => this.questions = result);}}

子组件Html如下.

<form (ngSubmit)="onSubmit()" [formGroup]="form"><div *ngFor="let question of questions" class="form-row"><div *ngIf="问题"><app-question [question]="question" [form]="form"></app-question>

</表单>

子组件如下

Class ChildComponent 实现 AfterViewInit {@Input() 问题: QuestionBase[] = [];构造函数(){}ngAfterViewInit(){this.form = this.qcs.toFormGroup(this.questions);}}

有第二个子组件,它依赖于 childComponent 来创建控件.因此,控件仅在第二个子组件的 ngOnit 中填充,因此未创建控件.我尝试使用许多生命周期钩子,例如 OnInit、OnChanges 等.但实际上没有一个给我结果.我确定我遗漏了一些我无法弄清楚的东西.

类服务(){问题: QuestionsData[]=[];getQuestions(FormKey: 字符串) {var dbQuestions = this.af.list('/元素', {询问: {limitToLast: 200,orderByChild: 'formid',等于:FormKey}})dbQuestions.subscribe(快照=>{快照.forEach(elementData => {this.questions.push(新文本框问题({键:elementData.elementname,标签:elementData.displaytext,值:elementData.elementvalue,要求:假,顺序: elementData.sortorder}))}}}

解决方案

看这个例子 Angular.io - 动态表单,它本质上是在运行时根据元数据构建表单.

有几条评论表明示例还没有完成.

@Injectable()导出类 QuestionService {//Todo:从问题元数据的远程来源获取//待办事项:使异步获取问题(){...

这些是我完成它并清除错误消息所采取的步骤.


question.service.ts

getQuestions 更改为异步返回问题.

Injectable()导出类 QuestionService {构造函数(私有 http: Http) {}getQuestions$() {const url = 'https://api.myjson.com/bins/d0srd';返回 this.http.get(url).map(response => response.json()).map(questionMetadata => this.metadataToQuestions(questionMetadata)).map(questions => questions.sort((a, b) => a.order - b.order))}私有元数据到问题(问题元数据){返回 questionMetadata.questions.map(this.toQuestion)}私人到问题(元素数据){//扩展其他控件类型返回新的文本框问题({键:elementData.elementname,标签:elementData.displaytext,值:elementData.elementvalue,要求:假,顺序: elementData.sortorder})}}


app.component.ts

将变量 questions 类型更改为 observable,将异步管道添加到模板.

@Component({...模板:`<div><h2>英雄的工作申请</h2><app-dynamic-form [questions]="(questions$ | async)"></app-dynamic-form>

`,...})导出类 AppComponent 实现 OnInit {问题$: Observable;构造函数(私人问题服务:QuestionService) {}ngOnInit() {this.questions$ = this.questionService.getQuestions$();}}


dynamic-form.component.ts

将@Input 变量questions 更改为设置/获取样式,以处理初始空值.
将创建表单的钩子从 ngOnInit 更改为 ngOnChanges 以处理问题的异步到达.

导出类 DynamicFormComponent 实现 OnChanges {私人_问题= [];@输入()设置问题(值:任何[]){this._questions = 值 ||[];}得到问题():任何[] {返回 this._questions;}...ngOnChanges() {this.form = this.qcs.toFormGroup(this.questions);}}


dynamic-form-question.component.ts

isValid getter 添加额外的检查以确保被验证的控件存在.

导出类 DynamicFormQuestionComponent {...get isValid() { return this.form.controls[this.question.key]?this.form.controls[this.question.key].valid : true;}}

To be very short i am using this Plunker I have a scenario where i have to create controls dynamically by reading the elements data from a service. So when i read the data from the service its asynchronous.But i have to create some concrete objects based on the data i receive from the service and pass it to the child components. So here is my logic

Html for the Main Component is as below.

   <ion-content padding class="container" *ngIf="questions"> 

   <app-dynamic-form [questions]="questions"></app-dynamic-form>

   </ion-content>

Class for the Main Component is below

Class ComponentMain{

   @Input() questions: QuestionBase<any>[]=[];
  constructor(public navCtrl: NavController, public navParams: NavParams,private qcs: Service)
    {
      qcs.getQuestions(this.parameter1.$key).subscribe(result => this.questions = result);
    }

}

Child Components Html is as follows.

<div *ngIf="form">
  <form (ngSubmit)="onSubmit()" [formGroup]="form">

    <div *ngFor="let question of questions" class="form-row">
      <div *ngIf="question">
        <app-question [question]="question" [form]="form"></app-question>
      </div>
   </div>
</form>
</div>

Child Component is as follows

Class ChildComponent implements AfterViewInit {

  @Input() questions: QuestionBase<any>[] = [];

 Constructor(){

  }

 ngAfterViewInit(){

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

 }

}

There is a 2nd child component which depends on childComponent to create the controls. So the controls are getting populated only in ngOnit of the 2nd child Component and due to which the controls are not getting created. I tried to use many life cycle hooks such as OnInit,OnChanges etc. But none of them actually gave me the result. I am sure i am missing something that i am unable to figure it out.

Class Service(){

questions: QuestionsData<any>[]=[];

getQuestions(FormKey: string) {

var dbQuestions = this.af.list('/elements', {
   query: {
   limitToLast: 200,
   orderByChild: 'formid',
   equalTo: FormKey
  }
})

  dbQuestions.subscribe(snapshots=>{
  snapshots.forEach(elementData => {
  this.questions.push(new TextboxQuestion({
        key: elementData.elementname,
        label: elementData.displaytext,
        value: elementData.elementvalue,
        required: false,
        order: elementData.sortorder
      }))
  }
 }
}

解决方案

Looking at this example Angular.io - Dynamic Forms, it essentially builds a form from metadata at runtime.

There's a couple of comments indicating that the example isn't quite finished.

@Injectable()
export class QuestionService {

  // Todo: get from a remote source of question metadata
  // Todo: make asynchronous
  getQuestions() {
  ...

These are the steps I took to finish it off and clean out the error messages.


question.service.ts

Changed getQuestions to asynchronously return questions.

Injectable()
export class QuestionService {

  constructor(
    private http: Http
  ) {}

  getQuestions$() {
    const url = 'https://api.myjson.com/bins/d0srd';
    return this.http.get(url)
      .map(response => response.json())
      .map(questionMetadata => this.metadataToQuestions(questionMetadata))
      .map(questions => questions.sort((a, b) => a.order - b.order))
  }

  private metadataToQuestions(questionMetadata) {
    return questionMetadata.questions.map(this.toQuestion)
  }

  private toQuestion(elementData) {
    // expand for additional control types
    return new TextboxQuestion({
      key: elementData.elementname,
      label: elementData.displaytext,
      value: elementData.elementvalue,
      required: false,
      order: elementData.sortorder
    })
  }
}


app.component.ts

Changed variable questions type to observable, added async pipe to template.

@Component({
  ...
  template: `
    <div>
      <h2>Job Application for Heroes</h2>
      <app-dynamic-form [questions]="(questions$ | async)"></app-dynamic-form>
    </div>
  `,
  ...
})
export class AppComponent implements OnInit {

  questions$: Observable<any>;

  constructor(
    private questionService: QuestionService
  ) {}

  ngOnInit() {
    this.questions$ = this.questionService.getQuestions$();
  }
}


dynamic-form.component.ts

Changed @Input variable questions to be set/get style, to handle initial null value.
Changed hook where form is created from ngOnInit to ngOnChanges to handle async arrival of questions.

export class DynamicFormComponent implements OnChanges {

  private _questions = [];
  @Input() 
  set questions(value: any[]) {
    this._questions = value || [];
  }
  get questions(): any[] {
    return this._questions;
  }

  ...

  ngOnChanges() {
    this.form = this.qcs.toFormGroup(this.questions);
  }

}


dynamic-form-question.component.ts

Add additional check to isValid getter to ensure the control being validated exists.

export class DynamicFormQuestionComponent {
  ...
  get isValid() { return this.form.controls[this.question.key] 
    ? this.form.controls[this.question.key].valid : true; }
}

这篇关于将数据从服务传递到组件 -->子组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆