Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

connecting a custom form control to its parent form validation in angular 2

I recently tried to create my own custom form control using angular 2. The custom control should have 2 inputs, and edit an existing object with a known structure. For example:

class model {
    public fieldOne: number;
    public fieldSec: number;
}

I followed the good explanation I found here: Guide For Writing custom form controls

It worked alright except the guide didn't mention how I can connect custom control form validation to the form that uses it. Lets look at an simplified example:

The custom control template looks somehow like this:

<form>
    <input [(ngModel)]="existingModel.fieldOne">
    <input [(ngModel)]="existingModel.fieldSec" required>
</form>

And we use it to edit an existing model which value is:

{
    fieldOne: 20,
    fieldSec: undefined
}

And we use it in some form in my app where we need the custom control to edit this model:

<form #formVar="ngForm">
    <my-custom-control [(ngModel)]="existingModel" required>
    </my-custom-control>
</form>

This kind of example works in my app in the matter that I can edit the model. The problem is that I want to show the user when the form is invalid, and if I look at formVar.valid it will be true even though existingModel.fieldSec is undefined and it has a required validation on it in the custom control form.

like image 901
Ziv Glazer Avatar asked Sep 11 '16 13:09

Ziv Glazer


People also ask

How do I add validation in template driven form?

To add validation to a template-driven form, you add the same validation attributes as you would with native HTML form validation. Angular uses directives to match these attributes with validator functions in the framework.

Which method is used to add dynamic validation to the forms?

The FormGroup class exposes an API that enables us to set validators dynamically. We need to listen to optionB value changes and based on that we add or remove the validators we require. We also call the control's updateValueAndValidity() method, as we need to recalculate the value and validation status of the control.


1 Answers

I don't know exactly how your custom control behaves, but the following solution is valid even if you're dynamically compiling the component itself.

Even in a scenario of template-driven forms (like yours), the underlying engine still works by exploiting reactive components (FormGroup and FormControl). Thus, you can always programmatically change the hierarchies of groups and child controls to propagate the changes as expected. You could - for instance - expose among others a property for your custom control accepting an NgForm:

@Input('form') peerForm : NgForm;
@Input('entity') model : any;

Then set the binding in your view:

<form #formVar="ngForm">
<my-custom-control [entity]="existingModel" [form]="formVar">
</my-custom-control></form>

Your component template should look like:

<div>
<input [(ngModel)]="model.fieldOne" #ctrl1="ngModel">
<input [(ngModel)]="model.fieldSec" required #ctrl2="ngModel">
</div>

And, again in your component's code:

@ViewChild('ctrl1') ngModel1 : NgModel;
@ViewChild('ctrl2') ngModel2 : NgModel;
...
ngAfterViewInit(){
    // assuming the form does exist (TODO: check if set here)
    this.peerForm.control.addControl('entity_fieldOne', this.ngModel1.control);
    this.peerForm.control.addControl('entity_fieldSec', this.ngModel2.control);
}

That should suffice. See Plunker here: https://plnkr.co/gb3XroZNoGuZa05e76X0

like image 118
Cristian Merighi Avatar answered Sep 17 '22 18:09

Cristian Merighi