The answer above is spot on, however I encountered a few deeper issues with this implementation in my particular use case, and so I solved it with a shared service:
form-management.service.ts
import { Injectable } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class FormManagementService {
private formSource: Subject<FormGroup> = new Subject();
locationForm: Observable<FormGroup> = this.formSource.asObservable();
formReady(form: FormGroup): void {
this.formSource.next(form);
}
}
parent.component.ts
import { Component } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormManagementService } from './form-management.service';
@Component({
....
providers: [ FormManagementService ]
})
export class ParentComponent {
form: FormGroup;
constructor(private formManagementService: FormManagementService) {
this.formManagementService.locationForm.subscribe(form => this.form = form);
}
}
Note, here we are subscribing to changes on the shared service, which will pass a form into the component when we need it. When the parent component receives the form, it populates the FormGroup.
Also note that we are providing the shared service here as part of the component decorator. You can also provide it in your feature module, if that's the way your code is structured.
child.component.ts
import { Component } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { FormManagementService } from './form-management.service';
@Component({ ... })
export class ChildComponent {
form: FormGroup;
constructor(private formManagementService: FormManagementService,
private formBuilder: FormBuilder) {
this.form = this.formBuilder.group({});
this.formManagementService.formReady(this.form);
}
}
Here in the child component we initialise the form and then push it through the shared service, which will in turn populate it in the parent component.
Note, I found that if I did this anywhere other than the constructor I encountered the ExpressionChangedAfterItHasBeenCheckedError
, even when I did this in ngAfterContentInit
. Perhaps someone else will have a further advancement on my solution to resolve this.
Anyway, hope this is of some help to someone out there, as this issue had been plaguing me for a couple of weeks.