Vahid
Vahid

Reputation: 1939

Ionic 2 form validation issue with formGroup and ngModel

I was trying to implement what seemed to be a straightforward form validation routine following this walk-through on my ionic 2 projects.

In my controller's constructor I used the FormBuilder like this to make a formGroup:

this.form = formBuilder.group({
  date: ['', Validators.required],
  client: ['', Validators.required]
});

And then in the template I added formControllerName attribute to relevant elements like this:

<ion-select formControlName="client" [(ngModel)]="clientId">

And bound the root element to the 'formGroup` like this:

<ion-content [formGroup]="form">

This fails with the following error message:

ngModel cannot be used to register form controls with a parent formGroup directive. Try using formGroup's partner directive "formControlName" instead. Example:

<div [formGroup]="myGroup">
  <input formControlName="firstName">
</div>

In your class:

this.myGroup = new FormGroup({
   firstName: new FormControl()
});

  Or, if you'd like to avoid registering this form control, indicate that it's standalone in ngModelOptions:

  Example:


<div [formGroup]="myGroup">
   <input formControlName="firstName">
   <input [(ngModel)]="showMoreControls" [ngModelOptions]="{standalone: true}">
</div>

As suggested by the error message, as well as this StackOverflow thread I added [ngModelOptions]="{standalone: true}" to my inputs but it came back with another error message:

Template parse errors: Can't bind to 'ngModelOptions' since it isn't a known property of 'ion-select'.

Upvotes: 3

Views: 3996

Answers (1)

Amit
Amit

Reputation: 4353

In angular2 you can choose to either use the "old" (more AngularJS-y) template-driven way, by using [(ngModel)] to create two-way bindings with your component variables:

Component:

private clientId: string;

Template:

<form>
    <input [(ngModel)]="clientId" required />
</form>

If I got facts together, this will behind-the-scenes create a FormGroup instance for the <form> element, and a FormControl instance for each input in it. The required directive will then apply a validator on it and trigger validation (and for example apply ng-valid/invalid accordingly).

Using this approach you can grab the value simply using clientId.

Using the model-driven (or "reactive") approach is by defining the form's "schema" using FormBuilder or simply creating instances of FormGroup and FormControl...

It would look something like this:

Component:

private form: FormGroup;

ngOnInit() {
    this.form = new FormGroup({
        clientId: new FormControl('', [Validators.required])
    });
}

Template:

<form [formGroup]="form">
    <input formControlName="clientId" />
</form>

In this case, if you want the entire form's value, you'd access (this.)form.value which in this example will return an object like this:

 { clientId: "whatever" }

Or if you only want the inner control's value, grab (this.)form.controls['clientId'].value.

Hope I made things clearer and not worse :)

EDIT: Using the latter approach means you can access an Observable of the FormControl and do some interesting things, for example:

let debouncedInput$ = this.form.control['clientId'].valueChanges.debounceTime(1000);

Upvotes: 6

Related Questions