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

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

问题描述

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

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如下.

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 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如下.

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>

子组件如下

Class ChildComponent implements AfterViewInit {

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

 Constructor(){

  }

 ngAfterViewInit(){

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

 }

}

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

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
      }))
  }
 }
}

推荐答案

看此示例 Angular.io-动态表单,它实际上是在运行时从元数据构建表单.

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.


已更改getQuestions以异步返回问题.

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
    })
  }
}


将变量questions的类型更改为可观察,并向模板添加了异步管道.

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$();
  }
}


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

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);
  }

}


isValid获取器中添加其他检查,以确保要验证的控件存在.

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天全站免登陆