I want to create a Angular
generic composite component which is composed of bunch of input fields which could be used inside multiple components across applicat
So, to your child components you can pass form
and add/remove controls to him.
Parent component template
<form (ngSubmit)="onSubmit(form)" #form="ngForm">
<a-comp [prop1]="name" [form]=form></a-comp>
<button type="submit">Submit</button>
</form>
Some child component:
// a comp
@Component({
selector: 'a-comp',
template: `
<input [(ngModel)]="prop1" name="name2" #myControl="ngModel"/>
`
})
export class AComponent {
@Input() form: NgForm;
@Input() prop1 = 'Angular 5';
@ViewChild('myControl') myControl: NgModel;
ngOnInit() {
//console.log(this.form, this.myControl);
this.form.addControl(this.myControl);
}
}
CODE EXAMPLE
Passing @Input
to childs isn't necessary. But child components need to know about form
.
2. Easiest way. By using power of DI
Child-component. In your case UserDetails:
@Component({
selector: 'a-comp',
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],
template: `
<input [(ngModel)]="prop1" name="prop1"/>
<input [(ngModel)]="prop2" name="prop2"/>
`
})
export class AComponent {
prop1 = 'Hello';
prop2 = 'World';
ngOnInit() { }
}
As you can see in @Component
decorators we set viewProviders
. So when requiring ControlContainer
we say to useExisting: NgForm
. By Angular DI
system it will go up to find first parent NgForm
.
ViewProviders = Defines the set of injectable objects that are visible to its view DOM children.
...
You maybe can ask: By
DI
mechanism it should search provider up to root, but why it doesn't go up in hirearchy and find parentNgForm
?
Constuctor of ngModel
:
constructor(@Optional() @Host() parent: ControlContainer,
@Optional() @Self() @Inject(NG_VALIDATORS) validators: Array<Validator|ValidatorFn>,
@Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: Array<AsyncValidator|AsyncValidatorFn>,
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR)
valueAccessors: ControlValueAccessor[]) {
...
Pay attention to @Optional() @Host() parent: ControlContainer
. It's @Optional and @Host().
@Host - Specifies that an injector should retrieve a dependency from any injector until reaching the host element of the current component.
So, here @Host()
decorators restrics the ngModel
to search only up to host
component where ngModel
is allocated.
NgModel constructor
By this approach no need create @Input
binding in child components to get parent NgForm
and add NgModels controls manually.
StackBlitz EXAMPLE