Will extend this file.
signup-form.component.html
Creating Controls Explicitly
Upgrade form to angular form
signup-form.component.ts
import {Component} from '@angular/core';
import {Control, ControlGroup, Validators} from '@angular/common';
@Component({
selector: 'signup-form',
templateUrl: 'app/signup-form.component.html'
})
export class SignUpFormComponent {
// model driven forms
form = new ControlGroup({
username: new Control('',Validators.required),
password: new Control('',Validators.required)
});
signup(){
console.log(this.form.value); // returns a json object that contains all value in the form
}
}
signup-form.component.html
<form [ngFormModel]="form" (ngSubmit)="signup()">
<div class="form-group">
<label for="username">Username</label>
<input
id="username"
type="text"
class="form-control"
ngControl="username"
#username="ngForm">
<div
*ngIf="!username.valid"
class="alert alert-danger">Username is required</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
id="password"
type="text"
class="form-control"
ngControl="password"
#password="ngForm">
<div
*ngIf="!password.valid"
class="alert alert-danger">Password is required</div>
</div>
<button class="btn btn-primary" type="submit">Sign Up</button>
</form>
app.component.ts
import { Component } from '@angular/core';
import {SignUpFormComponent} from './signup-form.component'
@Component({
moduleId: module.id,
selector: 'app-root',
directives:[SignUpFormComponent],
template: `
<signup-form></signup-form>
`
})
export class AppComponent {
}
Using FormBuilder
in Signup-form.component.ts
export class SignUpFormComponent {
form: ControlGroup;
constructor(fb:FormBuilder){
// cleaner? compact?
fb.group({
username:['',Validators.required],
password:['',Validators.required]
});
}
/*
*/
signup(){
console.log(this.form.value); // returns a json object that contains all value in the form
}
}
Implementing Custom Validation
// assume username cannot contain a space
Create usernameValidators.ts
import {Control} from '@angular/common'
// can put this method anywhere, but better to put in a separate class
export class UsernameValidators{
// validation passes: return null
// validation fails: return {<validationRule>:<value>} key-value pair e.g. minlength
static cannotContainSpace(control: Control){
if(control.value.indexOf(' ') >= 0)
return { cannotContainSpace: true};
return null;
}
}
signup-form.component.html
<form [ngFormModel]="form" (ngSubmit)="signup()">
<div class="form-group">
<label for="username">Username</label>
<input
id="username"
type="text"
class="form-control"
ngControl="username"
#username="ngForm">
<div *ngIf="username.touched && username.errors">
<div
*ngIf="!username.errors.valid"
class="alert alert-danger">Username is required</div>
<div
*ngIf="username.errors.cannotContainSpace"
class="alert alert-danger">Username cannot contain spaces
</div>
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
id="password"
type="text"
class="form-control"
ngControl="password"
#password="ngForm">
<div
*ngIf="!password.valid"
class="alert alert-danger">Password is required</div>
</div>
<button class="btn btn-primary" type="submit">Sign Up</button>
</form>
Async Validation: server side validation e.g. check if username is unique
add in usernameValidators.ts
// method returns a promise. A promise represents the result of a asynochronous operation.
static shouldBeUnique(control: Control){ // promises
return new Promise((resolve,reject) => {
// call to server
setTimeout(function(){
if(control.value == "mosh")
resolve({shouldBeUnique: true})
else
resolve(null);
},1000)
});
}
Add in signup-form.component.html
<div
*ngIf="username.errors.shouldBeUnique"
class="alert alert-danger">This username is already taken.
</div>
Showing a loader image
<form [ngFormModel]="form" (ngSubmit)="signup()">
<div class="form-group">
<label for="username">Username</label>
<input
id="username"
type="text"
class="form-control"
ngControl="username"
#username="ngForm">
<div *ngIf="username.control.pending">Checking for uniqueness..</div>
<div *ngIf="username.touched && username.errors">
<div
*ngIf="!username.errors.valid"
class="alert alert-danger">Username is required</div>
<div
Validating Upon Form Submit
signup(){
// var result = authService.login(this.form.value)
this.form.find('username').setErrors({invalidLogin:true});
console.log(this.form.value); // returns a json object that contains all value in the form
}
Add in signup-form.component.html
<div *ngIf="username.touched && username.errors">
<div
*ngIf="username.errors.invalidLogin"
class="alert alert-danger">Username or password is invalid</div>
<div
Password Change Form
change-password-form.component.html
<form [ngFormModel]="form" (ngSubmit)="changePassword()">
<div class="form-group">
<label for="oldPassword">Current Password</label>
<input
id="oldPassword"
type="password"
class="form-control"
ngControl="oldPassword"
#oldPassword="ngForm">
<div *ngIf="oldPassword.touched && oldPassword.errors">
<div
*ngIf="oldPassword.errors.required"
class="alert alert-danger">Old password is required.</div>
<div
*ngIf="oldPassword.errors.validOldPassword"
class="alert alert-danger">Old password is incorrect.</div>
</div>
</div>
<div class="form-group">
<label for="newPassword">New Password</label>
<input
id="newPassword"
type="password"
class="form-control"
ngControl="newPassword"
#newPassword="ngForm">
<div *ngIf="newPassword.touched && newPassword.errors">
<div
*ngIf="newPassword.errors.required"
class="alert alert-danger">
New password is required.</div>
<div
*ngIf="newPassword.errors.complexPassword"
class="alert alert-danger">
New password should be minimum {{ newPassword.errors.complexPassword.minLength }} characters.</div>
</div>
</div>
<div class="form-group">
<label for="confirmPassword">Confirm Password</label>
<input
id="confirmPassword"
type="password"
class="form-control"
ngControl="confirmPassword"
#confirmPassword="ngForm">
<div
*ngIf="confirmPassword.touched && !confirmPassword.valid"
class="alert alert-danger">
Confirm the password.</div>
<!--
Note that here I'm checking for form.errors.passwordShouldMatch
because this validation is applied at the form itself.
-->
<div
*ngIf="confirmPassword.touched && form.errors && form.errors.passwordsShouldMatch"
class="alert alert-danger">
Passwords don't match.</div>
</div>
<button class="btn btn-primary" type="submit" [disabled]="!form.valid">Change Password</button>
</form>
change-password-form.component.ts
import {Component} from '@angular/core';
import {ControlGroup, Validators, FormBuilder} from '@angular/common';
import {PasswordValidators} from './passwordValidators';
@Component({
selector: 'change-password-form',
templateUrl: 'app/change-password-form.component.html'
})
export class ChangePasswordFormComponent {
form: ControlGroup;
constructor(fb: FormBuilder){
this.form = fb.group({
oldPassword: ['', Validators.required],
newPassword: ['', Validators.compose([
Validators.required,
PasswordValidators.complexPassword
])],
// Note that here is no need to apply complexPassword validator
// to confirm password field. It's sufficient to apply it only to
// new password field. Next, passwordsShouldMatch validator
// will compare confirm password with new password and this will
// implicitly enforce that confirm password should match complexity
// rules.
confirmPassword: ['', Validators.required]
}, { validator: PasswordValidators.passwordsShouldMatch });
}
changePassword(){
// Validating the oldPassword on submit. In a real-world application
// here, we'll use a service to call the server. The server would
// tell us that the old password does not match.
var oldPassword = this.form.find('oldPassword');
if (oldPassword.value != '1234')
oldPassword.setErrors({ validOldPassword: true });
if (this.form.valid)
alert("Password successfully changed.");
}
}
passwordValidators.ts
import {Control, ControlGroup} from '@angular/common';
export class PasswordValidators {
static complexPassword(control: Control){
const minLength = 5;
// We bypass this validation rule if the field is empty, assuming
// it is valid. At this point, the required validator will kick in
// and asks the user to type a value. With this technique, we'll
// display only a single validation message at a time, rather than:
//
// * This field is required.
// * Password doesn't match complexity rules.
//
if (control.value == '')
return null;
if (control.value.length < minLength)
// Note that I'm returning an object, instead of:
//
// return { complexPassword: true }
//
// This will give the client additional data about the
// validation and why it failed.
return {
complexPassword: {
minLength: minLength
}
};
return null;
}
static passwordsShouldMatch(group: ControlGroup){
var newPassword = group.find('newPassword').value;
var confirmPassword = group.find('confirmPassword').value;
// If either of these fields is empty, the validation
// will be bypassed. We expect the required validator to be
// applied first.
if (newPassword == '' || confirmPassword == '')
return null;
if (newPassword != confirmPassword)
return { passwordsShouldMatch: true };
return null;
}
}
No comments:
Post a Comment