Forms - just can find a working example

Hi
I am examining Ionic 2 these days and just cant find a working example of forms with validation.
I use beta 11.
Can anyone point such an example or can post a working forms code for beta 11 here in the forum ?

Thanks a lot

I’m also using beta 11 and below is the user details form that I have. It has 3 fields: name, email and phone with validators for each.

user-info.html

<ion-header>
  <ion-toolbar>
    <ion-title>User Details</ion-title>
  </ion-toolbar>
</ion-header>
<ion-content>
  <ion-list>
    <form [formGroup]="myForm" (ngSubmit)="onSubmit()">
      <ion-item>
        <ion-label floating primary>Name</ion-label>
        <ion-input [(ngModel)]="userInfo.name" formControlName="name" type="text"
                   id="name" spellcheck="false" autocapitalize="off">
        </ion-input>
      </ion-item>
      <p *ngIf="!isValid('name')" danger padding-left>Invalid Name</p>
      <ion-item>
        <ion-label floating primary>Email</ion-label>
        <ion-input [(ngModel)]="userInfo.email" formControlName="email"
                   type="text" id="email" spellcheck="false" autocapitalize="off">
        </ion-input>
      </ion-item>
      <p *ngIf="!isValid('email')" danger padding-left>Invalid Email</p>
      <ion-item>
        <ion-label floating primary>Phone</ion-label>
        <ion-input [(ngModel)]="userInfo.phone" formControlName="phone" type="text" id="phone">
        </ion-input>
      </ion-item>
      <p *ngIf="!isValid('phone')" danger padding-left>Invalid Phone</p>
      <button type="submit" block primary [disabled]="!myForm.valid">Submit</button>
    </form>
  </ion-list>
</ion-content>

user-info.ts

import {OnInit, Component} from "@angular/core";
import {FormGroup, FormBuilder, FormControl, Validators} from "@angular/forms";

@Component({
  templateUrl: 'build/pages/user-info/user-info.html'
})
export class UserInfoComponent implements OnInit {
  myForm: FormGroup;
  userInfo: {name: string, email: string, phone: string} = {name: '', email: '', phone: ''};

  constructor(public formBuilder: FormBuilder) {
  }

  ngOnInit(): any {
    this.myForm = this.formBuilder.group({
      'name': ['', [Validators.required, Validators.minLength(3), this.nameValidator.bind(this)]],
      'phone': ['', this.phoneValidator.bind(this)],
      'email': ['', [Validators.required, this.emailValidator.bind(this)]]
    });
  }

  onSubmit() {
    console.log('submitting form');
  }

  isValid(field: string) {
    let formField = this.myForm.find(field);
    return formField.valid || formField.pristine;
  }

  nameValidator(control: FormControl): {[s: string]: boolean} {
    if (!control.value.match("^[a-zA-Z ,.'-]+$")) {
      return {invalidName: true};
    }
  }

  phoneValidator(control: FormControl): {[s: string]: boolean} {
    if (control.value !== '') {
      if (!control.value.match('\\(?\\d{3}\\)?-? *\\d{3}-? *-?\\d{4}')) {
        return {invalidPhone: true};
      }
    }
  }

  emailValidator(control: FormControl): {[s: string]: boolean} {
    if (!(control.value.toLowerCase().match('^[a-zA-Z]\\w*@gmail\\.com$') || control.value.toLowerCase().match('^[a-zA-Z]\\w*@yahoo\\.com$'))) {
      return {invalidEmail: true};
    }
  }
}
5 Likes

Hi
I will try it
Thanks a lot.

Is it possible to work with FormsModule or ReactiveFormsModule from @angular/forms in Ionic ?
Thanks

The given example is an implementation of ReactiveFormsModule. formControlName is used is ReactiveForms

Thanks.
I was confused because I couldn’t find an import {ReactiveFormsModule} from '@angular/forms' statement.
That brings me to the question: Where it is done ?
Where is @NgModule in an Ionic app ? And how ReactiveFormsModule is imported to it using the “imports:” property ?

Thanks again.

There is no NgModule in ionic 2 yet, may be coming in beta 12

Follow these links to get knowledge of Forms in Angular2. And implement in Ionic2 with little modifications as per your requirement.

TEMPLATE-DRIVEN FORMS IN ANGULAR 2

REACTIVE FORMS IN ANGULAR 2

Template Driven vs Model Driven or Reactive Forms - Angular University blog

1 Like

Thanks a lot for the great links.

Since ankushagg93 made it clear that ReactiveFormsModule is available in 11 beta I tried to modify angular2 cookbook on form validation from:
https://angular.io/docs/ts/latest/cookbook/form-validation.html.

Basically it works. But there are 2 problems:

  1. The form is by default not valid. Why ?
  2. I did not define any validation css, but a failed validation is displayed by ugly stripes. Where are those coming from ?

html

    <ion-item>
        <ion-label floating>Email</ion-label>
        <ion-input type="text" formControlName="email" required></ion-input>
    </ion-item>
    <div *ngIf="formErrors.email" class="alert alert-danger">
        {{ formErrors.email }}
    </div>


    <ion-item>
        <ion-label floating>Password</ion-label>
        <ion-input type="password" formControlName="password" required></ion-input>
    </ion-item>
    <div *ngIf="formErrors.password" class="alert alert-danger">
        {{ formErrors.password }}
    </div>     


    <ion-item>
        <ion-label floating>Retype Password</ion-label>
        <ion-input type="password" formControlName="passwordMatch" required></ion-input>
    </ion-item>
    <div *ngIf="formErrors.passwordMatch" class="alert alert-danger">
        {{ formErrors.passwordMatch }}
    </div>

    <button block outline large type="submit" [disabled]="!registerForm.valid">Register</button>
    {{ registerForm.valid }}
</form>

TS
import { Component, OnInit } from ‘@angular/core’;
import { NavController } from ‘ionic-angular’;
import {FormGroup, FormBuilder, Validators} from ‘@angular/forms’;

@Component({
templateUrl: 'build/pages/register/register.html'    
})

export class Register implements OnInit {

registerInfo = {
    email: '',
    password: ''
} 


constructor(private navController: NavController, private fb: FormBuilder) { }


active: Boolean;
registerForm: FormGroup;   

ngOnInit(): void {
    this.active = true;
    this.buildForm();        
}

buildForm(): void {
   this.registerForm = this.fb.group({
        'email': [this.registerInfo.email, [
            Validators.required 
        ]
        ],
        'password': [this.registerInfo.password, [
            Validators.required
            
        ]
        ],
        'passwordMatch': [this.registerInfo.password, [
            Validators.required
        ]
        ]
    });    


    this.registerForm.valueChanges.subscribe(data => this.onValueChanged(data));
    this.onValueChanged(); 
}


onSubmit() {        
    this.registerInfo = this.registerForm.value;
}



onValueChanged(data?: any) {
    if (!this.registerForm) {
        return;
    }        
    const form = this.registerForm;
    if (form.pristine) {
        return;
    }
    if (!form.dirty) {
        return;
    }
    for (const field in this.formErrors) {
        // clear previous error message (if any)
        this.formErrors[field] = '';
        const control = form.controls[field];
        if (control && control.dirty && !control.valid) {
            const messages = this.validationMessages[field];
            for (const key in control.errors) {
                this.formErrors[field] += messages[key] + ' ';
            }
        }
    }
}
formErrors = {
    'email': '',
    'password': '',
    'passwordMatch': ''
};
validationMessages = {
    'email': {
        'required': 'Email is required.',            
        'emailPattern': 'Email is not valid'
    },
    'password': {
        'required': 'Password is required.'
    },
    'passwordMatch': {
        'required': 'Retype password',
        'match':'Passwords do not match'
    }
};
}

Result
image

I don’t understand this function especially {[s: string]: boolean} section.
Would you declare it?

It’s just regex matching that I want for my name validator. This regex only allows one or more of following characters a-zA-Z ,.'-

Regarding {[s: string]: boolean} , it’s just return type for TypeScript. You can remove it if you want. It means the validator will return an object with key value pair where key is string and value is boolean. Actually I’m returning wrong, key should be string return {'invalidName': true}; Again, it’s just developer choice.

For angular, any non-null return value means validation failed.

2 Likes

How can I know my angular version inside ionic?

I think you can do ionic info to see Ionic Framework Version and then look in package.json to find out angular version.

Does this work in RC1 when building Android?
When I use the following, I get an error ( see beneath ) when running Android:

    formInfo = {
name: '',
slogan: '',
category: ''
}
this.myForm = formBuilder.group({
'name': [this.formInfo.name, Validators.required]
'slogan': '',
'category': [this.formInfo.category, Validators.required]
})

Errors:
Property ‘name’ does not exist on type '{ key string] :AbstractControl
Property ‘category’ does not exist on type '{ key string] :AbstractControl

No error for slogan as is not required.

My ionic info:

Cordova CLI: 6.3.1
Gulp version: CLI version 3.9.0
Gulp local:
Ionic Framework Version: 2.0.0-rc.1
Ionic CLI Version: 2.1.1
Ionic App Lib Version: 2.1.1
Ionic App Scripts Version: 0.0.36
OS:
Node Version: v6.8.0

Thanks @ankushagg93! This is awesome :smiley:

@Ankush ,I did same as you but changed little bit code to render different messages at interface a/c to Preformatted texterror.
every time i was stopped with an issue like

TypeError: Cannot read property ‘firstname’ of undefined TypeError: Cannot read property ‘firstname’ of undefined at Object.View_RegisterPage_0.co [as updateDirectives]

Here is my code
`
Register.ts
import { OnInit, Component} from ‘@angular/core’;
import { NavController } from ‘ionic-angular’;

//import { LoginPage } from ‘…/…/pages/login/login’;
import { FormGroup, FormBuilder, FormControl, Validators, FORM_DIRECTIVES } from “@angular/forms”;

@Component({

   selector: 'page-registration',
   templateUrl: 'registration.html',

})
export class RegisterPage implements OnInit {

                myForm: FormGroup;
                userInfo: { firstname: string } = { firstname: '' };


constructor(public navCtrl: NavController, public formBuilder: FormBuilder) {

   
}

ngOnInit(): any {

    this.myForm = this.formBuilder.group({
        'firstname': ['', Validators.compose([Validators.required, Validators.minLength(3), Validators.maxLength(15), this.firstnameValidator.bind(this)])]
     
    }); 
    
      
}

onSubmit() {
    console.log('submitting form');
} 


isValid(field: string) {
    let formField = this.myForm.get(field);
    return formField.valid || formField.pristine;
}

firstnameValidator(control) {
    const regExp = new RegExp(/^[a-zA-Z0-9]+$/);
   
    if (regExp.test(control.value)) {
        return null; // Return as valid username
    } else {
        return { 'validatefirstname': true } 
    }
}


goBack() {
    
    this.navCtrl.pop();
}

}

.`
register.html

<ion-item>
  <ion-label floating primary>FirstName</ion-label>
  <div [ngClass]="{'has-error': (myForm.control.firstname.errors && myForm.control.firstname.dirty), 'has-success': !myForm.control.firstname.errors}">
    <ion-input [(ngModel)]="userInfo.firstname" formControlName="firstname" type="text"
               id="firstname" spellcheck="false" autocapitalize="off">
    </ion-input>
  </div>
  <p *ngIf="form.control.firstname.errors?.required && form.control.firstname.dirty">This field is required</p>

Minimum characters: 3, Maximum characters: 15

firstnamemust not have any special characters

  <div padding>
    <button ion-button color="primary" class="submit-btn" full type="submit"
            [disabled]="!myForm.valid" block>
      Register
    </button>
  </div>
</ion-col>
Login

Please help me to get out of this.

Thanks men, helped me a lot!!!

Anybody coming across this thread, don’t emulate this. Dot access to controls will break in production mode. Use get() instead.