angular - 将数据从服务传递到组件 --> 子组件

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

}

子组件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 中填充,因此不会创建控件。我尝试使用许多生命周期钩子(Hook),例如 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
      }))
  }
 }
}

最佳答案

看这个例子Angular.io - Dynamic Forms ,它本质上是在运行时从元数据构建一个表单。

有一些注释表明该示例尚未完成。

@Injectable()
export class QuestionService {

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

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


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


动态表单.component.ts

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

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

}


动态表单问题.component.ts

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

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

关于angular - 将数据从服务传递到组件 --> 子组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48372635/

相关文章:

Angular + firebase auth + Material =路由器崩溃

c# - 为什么使用 Google Cloud Firestore 1.0.0-beta05 C# SetAsync 时会出现 Grpc.Core.RpcException StatusCode=Unavailable, Detail ="Connect Failed"?

angular - 自定义实体的 ngbTypeahead

javascript - 在事件流中等待安静期的 RxJS 运算符,但在事件流繁忙的情况下不会永远等待

angular - 如何在输入焦点上动态控制 Angular 2+ 中父元素的类?

ios - Firebase 查询 - 查找包含字符串的子项目

angular - 提供常量

angular - 缓冲 Angular 服务 HttpClient 请求

Angular 2 : replace host element with component's template

android - Cordova位置权限每次都会触发onResume