Using this resource, I want to implement formControlName up multiple nested levels.
Angular 2 - formControlName inside component
Say the actual formGroup lives 3 component levels above a child formControlName component,
ControlValueAccessor works if the Parent component is right next to child. However multiple levels above (grandfather) form does not work.
Is there an alternative to Service, or multiple input/outputs ? Or are these the only method?
A--> Component with formGroup
B---> Component container
C---> Component container
D ---> Component with FormControlName (should pass to Component A)
Component A will collect multiple form control names from different children components similar to this,
InputText.ts
export class InputTextComponent implements AfterViewInit, ControlValueAccessor {
@Input() disabled: boolean;
@Output() saveValue = new EventEmitter();
value: string;
onChange: () => void;
onTouched: () => void;
writeValue(value: any) {
this.value = value ? value : "";
}
registerOnChange(fn: any) {this.onChange = fn}
registerOnTouched(fn: any) {this.onTouched = fn}
setDisabledState(isDisabled) {this.disabled = isDisabled}
}
InputText.html
<input .. />
Using this resource, I want to implement formControlName up multiple nested levels.
Angular 2 - formControlName inside component
Say the actual formGroup lives 3 component levels above a child formControlName component,
ControlValueAccessor works if the Parent component is right next to child. However multiple levels above (grandfather) form does not work.
Is there an alternative to Service, or multiple input/outputs ? Or are these the only method?
A--> Component with formGroup
B---> Component container
C---> Component container
D ---> Component with FormControlName (should pass to Component A)
Component A will collect multiple form control names from different children components similar to this,
InputText.ts
export class InputTextComponent implements AfterViewInit, ControlValueAccessor {
@Input() disabled: boolean;
@Output() saveValue = new EventEmitter();
value: string;
onChange: () => void;
onTouched: () => void;
writeValue(value: any) {
this.value = value ? value : "";
}
registerOnChange(fn: any) {this.onChange = fn}
registerOnTouched(fn: any) {this.onTouched = fn}
setDisabledState(isDisabled) {this.disabled = isDisabled}
}
InputText.html
<input .. />
Share
Improve this question
edited Nov 10, 2019 at 4:12
asked Nov 5, 2019 at 8:47
user12250118user12250118
4
|
2 Answers
Reset to default 18 +25You can consider four options:
1) provide ControlContainer on your component with FormControlName
d.component.ts
@Component({
...
viewProviders: [
{
provide: ControlContainer,
useExisting: FormGroupDirective
}
]
})
export class DComponent implements OnInit {
Ng-run Example
2) create simple directive that provides ControlContainer
@Directive({
selector: '[provideContainer]',
providers: [
{
provide: ControlContainer,
useExisting: FormGroupDirective
}
]
})
export class ProvideContainerDirective {
}
then place this directive somewhere at the top of nodes hierarchy in your
d.component.html
<ng-container provideContainer>
<input formControlName="someName">
</ng-container>
Ng-run Example
3) use FormControlDirective instead of FormControlName directive
FormControlDirective requires FormControl instance to be passed
<input [formControl]="control">
You can get this instance either though DI:
d.component.ts
export class DComponent implements OnInit {
control;
constructor(private parentFormGroupDir: FormGroupDirective) { }
ngOnInit() {
this.control = this.parentFormGroupDir.control.get('someName');
}
Ng-run Example
or use some service that ties your components.
d.component.ts
export class DComponent implements OnInit {
control: FormControl;
constructor(private formService: FormService) { }
ngOnInit() {
this.control = this.formService.get('someName');
}
Ng-run Example
4) pass FormGroup as Input props down to the children or get it through DI or service and then wrap your input[formControlName] with formGroup directive
d.component.html
<ng-container [formGroup]="formGroup">
<input formControlName="..."
</ng-container>
Ng-run Example
Stackblitz
i think this is what you're looking for
follow the stackblitz example
I've created 3 components comp1
comp2
comp3
I've created the signup form in appModule
and passing the formGroup
to comp1
=> comp2
=> comp3
In comp3
I've created formControl
of age
property and binding it.
On changing the value of age
from comp3
it will get reflected in parent component, that is appComponent
Hope this helps!
Cheers!
formControlName
you can simply useformControl.get('path.to.prop')
for the controls. – Sergey Commented Nov 9, 2019 at 22:30