非常简短,我正在使用此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
}))
}
}
}
答案 0 :(得分:2)
查看此示例Angular.io - Dynamic Forms,它实质上是在运行时从元数据构建表单。
有几条评论表明这个例子还没有完成。
@Injectable()
export class QuestionService {
// Todo: get from a remote source of question metadata
// Todo: make asynchronous
getQuestions() {
...
这些是我完成它并清除错误消息所采取的步骤。
更改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
})
}
}
将变量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$();
}
}
将@Input变量questions
更改为set / get style,以处理初始空值
更改了从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);
}
}
向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();
}
}
我希望这可以帮到你。