Search code examples
angularangular4-forms

Reactive forms: how to pass a reference of a FormControl to its child so it can register a value change listener?


If I use template-driven forms I can inject a reference of a FormControl to an "error-message" component. Note the use of the ngModel directive (see this tutorial).

<input type="text" name="myFormControl" #myFormControl="ngModel" ngModel />
<error-message [control]="myFormControl" key="foo.bar" />

This almost works with reactive forms (I have to use the formControlName directive but I can't use that ngModel stuff).

<input type="text" formControlName="myFormControl" #myFormControl />
<error-message [control]="myFormControl" key="foo.bar" />

The "error-message" component receives the FormControl correctly (this.control is set) but this.control.valueChanges is undefined and I can't register a change event listener.

Does anyone know a way to pass a FormControl reference to its child with a reactive form so that I can register a valueChange listener ? I guess what's missing is this ngModel stuff but I don't know how to pass it around in a reactive form.

@Component({
    selector: 'error-message',
    ...
})
export class ErrorMessageComponent implements OnInit {
    @Input()
    private control: AbstractControl;
    @Input()
    private path: String;

    ngOnInit() {
        this.control.valueChanges.subscribe(() => hideErrorMessage());
    }
    ...
}

A bit more background information: The validation logic of the form data is exclusively implemented in the back-end of my application. Validation errors are sent as simple map entries . Each key equals to the path of a field of the data model. I wrote an "error-message" component that takes such a key as parameter and subscribes to some service so it can receive validation errors as they happen. I want this component to also hold a reference to its parent (i.e. a FormControl) so it can update its style if an error happens, and reset the error message if the user changes what he put in the FormControl.

We want to decouple things so that the parent doesn't know anything about its child (the "error-message" component).

My form is a simple reactive form build with a FormBuilder.

...
constructor(private formBuilder: FormBuilder) {}

ngOnInit() {
    this.myFormGroup = this.formBuilder.group({myFormControl: ''});
}
...

Solution

  • <form [formGroup]="myForm">
      <input type="text" formControlName="myControl" />
      <error-message [control]="myForm.get('myControl')" key="foo.bar" />
    </form>
    

    This should work.

    Also, I guess you could use the OnChanges interface to create a value change hook, but I don't know if it works on form controls, maybe you should pass the value only for that.

    Let me know if it works !