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 application.
For Example:
Consider a USER DETAIL component which has following Fields,
- Email - InputText Field
- Gender-Radio button.
- Age Group - A Dropdown
- Description - A Text Area.
I want to include this USER DETAIL
component in multiple components as below:
From Conventional wisdom I can say, that I just include <app-userdetails>
in multiple components.
But how Do I Handle the submitted FormGroupData
?
I mean how do I get the data from UserDetail
when its included in another component like CreateEmployee
?
I am not sure if I explained the above scenario properly, please point me to any web-examples or existing questions about this.
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 parent NgForm
?
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