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.
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.app.component.ts
Changed variable
questions
type to observable, added async pipe to template.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
tongOnChanges
to handle async arrival of questions.dynamic-form-question.component.ts
Add additional check to
isValid
getter to ensure the control being validated exists.I'm not sure that I have understand your problem but when I need to pass data from service to a component I use subscription in this way.
Two component (a parent component and its children or other different component) can share a service whose interface enables bi-directional communication.
Like in the Observer pattern, in this case the scope of the service instance is the notification from a component (Publisher) and other componentents (Subscriber).
mycomponent.service.ts
In the component who wants to notify all subscribers a change of its state:
mycomponent-publisher.ts
In the subscriber component who want to get the notification.
mycomponent-subscriber.ts
I hope that this can help you.