将数据从服务传递到组件 - >儿童组件

时间:2018-01-21 23:03:22

标签: angular firebase rxjs angular-services angular4-forms

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

主要组件的Html如下所示。

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

<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等。但它们都没有给我结果。我确信我错过了一些我无法弄清楚的事情。

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

2 个答案:

答案 0 :(得分:2)

查看此示例Angular.io - Dynamic Forms,它实质上是在运行时从元数据构建表单。

有几条评论表明这个例子还没有完成。

@Injectable()
export class QuestionService {

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

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


question.service.ts

更改getQuestions以异步方式返回问题。

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

将变量questions类型更改为可观察,将异步管道添加到模板。

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


动态form.component.ts

将@Input变量questions更改为set / get style,以处理初始空值 更改了从ngOnInitngOnChanges创建表单的挂钩,以处理问题的异步到达。

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

}


动态外形question.component.ts

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

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

答案 1 :(得分:0)

我不确定我是否理解您的问题,但当我需要将数据从服务传递到组件时,我就会以这种方式使用订阅。

两个组件(父组件及其子组件或其他不同组件)可以共享其接口支持双向通信的服务。

与Observer模式类似,在这种情况下,服务实例的范围是来自组件(Publisher)和其他组件(订阅者)的通知。

<强> mycomponent.service.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class MyComponentService{
    // Observable 
    private sampleObservable = new Subject<boolean>();
    // Observable boolean streams
    sampleSubscriber = this.sampleObservable.asObservable();
    // Event for notification from publisher to subscriber
    sampleEventChanged(value:boolean)
    {
        this.sampleObservable.next();
    }
}

在想要通知所有订户状态更改的组件中:

<强> myComponent的-publisher.ts

import { Component } from '@angular/core';
import { MyService } from './mycomponent.service';

@Component({
  selector: 'app-my-control-publisher',
  template: `
  <h2>This is the publisher control</h2>
  <button (click)="announce()">Announce to subscriber</button>
  `,
  providers: [MyService]
})

export class MyControlPublisherComponent 
{
  constructor(private myService: MyService) { }

  announce() 
  {
    this.myService.sampleEventChanged(true);
  }
}

在想要获取通知的订阅者组件中。

<强> myComponent的-subscriber.ts

import { Component, OnDestroy } from '@angular/core';
import { MyService } from './mycomponent.service';
import { Subscription } from 'rxjs/Subscription';

@Component({
 selector: 'app-my-control-subscriber',
 template: `
 <h2>This is the subscriber control</h2>
 `,
})

export class MyControlSubscriberComponent 
{
  // Subscriptions
  private componentSubscription: Subscription;

  constructor(private myService: MyService) 
  {
    // Subscription of the notifications
    this.componentSubscription= this.myService.sampleSubscriber.subscribe(value =>
    {
      // Put the code for manage the notification here
    }
  }

  ngOnDestroy()
  {
    // Release subscription to avoid memory leaks when the component is destroyed
    this.componentSubscription.unsubscribe();
  }
}

我希望这可以帮到你。