Angular 2.0 forms

38
AngularJS 2.0 Forms Eyal Vard Site: http://ng-course.o Blog: eyalVardi.wordpres.

Transcript of Angular 2.0 forms

Page 1: Angular 2.0 forms

AngularJS 2.0 Forms

Eyal Vardi

Site: http://ng-course.org

Blog: eyalVardi.wordpres.com

Page 2: Angular 2.0 forms

Agenda Template Driven

Two-way data binding with ngModel Change tracking with ngControl ngForm

Model Driven Control & ControlGroup Form Builder

Validations Value Accessors

Page 3: Angular 2.0 forms

Form Directives (Template Driven)

Installation The forms classes exist in

'angular2/common'import { FORM_DIRECTIVES } from 'angular2/common';

ngFormngFormModel

ngModelngControl

ngFormControl

Controls (Model Driven)

Valid

ator

s

Acce

ssor

s

ControlControlGroupControlArray

Page 4: Angular 2.0 forms

My Component

(Model)name: string

Form Control’s Classes

ControlControlGroupControlArray

Component View Template

<input type="text" [(ngModel)] ="name" />

pristine dirty touched untouche

d errors valid

Data Flow

Page 5: Angular 2.0 forms

Template Driven

Page 6: Angular 2.0 forms

ngModel Directive Binds an existing domain model to a

form control.@Component({ selector: "search-comp", directives: [FORM_DIRECTIVES], template: `<input type='text' [(ngModel)]="name">`})class SearchComp { name: string;}

Page 7: Angular 2.0 forms

Inside [(ngModel)] 1/2

<input type="text" class="form-control"

required

[ngModel]="model.name"

(ngModelChange)="model.name =

$event" >

Name: {{model.name}}

Property Binding, a value flows from the model to a target property on screen.

Event Binding, we flow the value from the target property on screen to the model.

Page 8: Angular 2.0 forms

Inside [(ngModel)] 2/2@Directive({ selector: '[ngModel]:not([ngControl]):not([ngFormControl])', bindings: [formControlBinding], inputs : ['model: ngModel'], outputs : ['update: ngModelChange'], exportAs: 'ngForm'})export class NgModel extends NgControl implements OnChanges { _control = new Control(); /** @internal */ _added = false; /** @internal */ update = new EventEmitter(); model: any; viewModel: any;

constructor(...) {...} /** Properties & Methods */ }

Page 9: Angular 2.0 forms

ngControl Directive (NgControlName) Creates and binds a control with a

specified name to a DOM element.

<form #f="ngForm" (submit)='onLogIn(f.value)'>

Login <input type='text' ngControl='login'

#l="ngForm">

<div *ngIf="!l.valid">Login is invalid</div>

</form>

Page 10: Angular 2.0 forms

Component Field

Component Template Directive that in use

name : string

<input [(ngModel)]=“name” /> ngModel

name : string

<input ngControl=“dName” [(ngModel)]=“name” />

ngControlName

ngModel vs. ngControlName ngControlName directive selector

'[ngControl]'

ngModel directive selector '[ngModel]:not([ngControl]):not([ngFormControl])

'

This is still a ngControl

Page 11: Angular 2.0 forms

ngControl Properties Properties:

formDirective control value path validator asyncValidator

States Properties: pristine dirty touched untouched errors valid

Abstract class

Page 12: Angular 2.0 forms

Track change-state and validity

State Class if true Class if false

Control has been visited ng-touched ng-untouched

Control's value has changed ng-dirty ng-pristine

Control's value is valid ng-valid ng-invalid

Page 13: Angular 2.0 forms

NgControlStatus Directive Sets CSS classes based on ngControl

directive status (valid/invalid/dirty/etc).@Directive({ selector: '[ngControl],[ngModel],[ngFormControl]', host: { '[class.ng-untouched]': 'ngClassUntouched', '[class.ng-touched]' : 'ngClassTouched', '[class.ng-pristine]' : 'ngClassPristine', '[class.ng-dirty]' : 'ngClassDirty', '[class.ng-valid]' : 'ngClassValid', '[class.ng-invalid]' : 'ngClassInvalid' }})export class NgControlStatus { private _cd: NgControl; constructor(@Self() cd: NgControl) { this._cd = cd; } ...

get ngClassValid(): boolean { return isPresent(this._cd.control) ? this._cd.control.valid : false; } ...}

Page 14: Angular 2.0 forms

Data BindingTrack change-state

and validity

Validators

Control

My Component (model)

Page 15: Angular 2.0 forms

ngModel Directives ngControlName

ngFormControl

ngModelselector :

'[ngModel]:not([ngControl]):not([ngFormControl])',Inputs : ['model: ngModel'],

outputs : ['update: ngModelChange'],

selector : '[ngFormControl]'inputs : ['form: ngFormControl', 'model: ngModel'],outputs : ['update: ngModelChange'],

selector : '[ngControl]',inputs : ['name: ngControl', 'model: ngModel'],outputs : ['update: ngModelChange'],

Page 16: Angular 2.0 forms

Form Tag & NgForm Directive NgForm will get automatically attached to

any <form> tags you have in your view, when we used FORM_DIRECTIVES. A ControlGroup named ngForm A (ngSubmit) output

<form #f="ngForm" (ngSubmit)="onSubmit(f.value)"></form>

ExportAs

Output

Page 17: Angular 2.0 forms

Form Directives

Use on input tagUse on form tag

Page 18: Angular 2.0 forms

Errors Messages Form message

Field message

Specific validation

<div *ngIf="!myForm.valid" class="ui error message">Form is invalid

</div>

<div *ngIf="!name.valid" class="ui message" [class.error]="!name.valid && name.touched" >

Name is invalid</div>

<div *ngIf="name.hasError('required')" class="ui error message">Name is required</div>

Page 19: Angular 2.0 forms

Model Driven

Page 20: Angular 2.0 forms

Form Controls `Control`s have values and validation

state

Page 21: Angular 2.0 forms

AbstractControl Class Events:

valueChanges statusChanges

Methods: setErrors,getErrors & hasErrors find setParent markAsDirty,markAsXXX runValidator

Properties: value status valid errors pristine dirty touched untouched

Page 22: Angular 2.0 forms

Model Driven Forms A Control represents a single input field Controls encapsulate the field's value,

and states such as if it is valid, dirty (changed), or has errors.

Directives Controls

ngFormModel ControlGroup | ControlArray

ngFormControl Control

Page 23: Angular 2.0 forms

ngFormModel & ngFormControl ngFormModel Binds an existing control

group to a DOM element. ngFormControl Binds an existing Control

to a DOM element.

export class App { constructor() { this.myForm = new ControlGroup({ myControl: new Control("") }); }}

<form [ngFormModel]="myForm"> <input ngFormControl="myControl"></form>

Page 24: Angular 2.0 forms

FormBuilder Class Creates a form object from a user-

specified configuration. control(value: Object, validator?: Function, asyncValidator?: Function) :

Control group(controls: {[key: string]: any}, extra?: {[key: string]: any}) :

ControlGroup array(controls: any[], validator?: Function, asyncValidator?: Function) :

ControlArrayconstructor(builder: FormBuilder) {

this.loginForm = builder.group({

login: ["", Validators.required],

passwordRetry: builder.group({

password: ["", Validators.required],

pConfirmation: ["", Validators.required]

})

});

}

Page 25: Angular 2.0 forms

FormBuilder Class Creates a form object from a user-

specified configuration.@Component({ selector: 'my-app', viewBindings: [FORM_BINDINGS], template: ` <form [ngFormModel]="loginForm"> <p>Login <input ngFormControl="login"></p> <div ngControlGroup="passwordRetry"> <p>Password <input type="password" ngFormControl="password"></p> <p>Confirm password <input type="password" ngFormControl="pConfirma"></p> </div> </form> <h3>Form value:</h3> <pre>{{value}}</pre> `, directives: [FORM_DIRECTIVES]})

export class App { loginForm: ControlGroup; constructor(builder: FormBuilder) { this.loginForm = builder.group({ login: ["", Validators.required], passwordRetry: builder.group({ password: ["", Validators.required], pConfirm: ["", Validators.required] }) }); } get value(): string { return JSON.stringify( this.loginForm.value, null, 2); }}

Page 26: Angular 2.0 forms

Watching For Changes Both ControlGroup and Control have an

EventEmitter that we can use to observe changes.this.name.valueChanges.subscribe( (value: string) => { console.log('name changed to: ', value); });

this.myForm.valueChanges.subscribe( (value: string) => { console.log('form changed to: ', value); });

Page 27: Angular 2.0 forms

Validations

Page 28: Angular 2.0 forms

Built-in Validators Required MaxLength & MinLength

Page 29: Angular 2.0 forms

Custom Validator Directive@Directive({ selector: ' [my-validator][ngControl],

[my-validator][ngFormControl], [my-validator][ngModel]', providers: [provide( NG_VALIDATORS, { useExisting: myValidator, multi: true})]})export class myValidator implements Validator { private _validator: Function;

constructor(@Attribute("my-validator") myValidator: string) { this._validator = function(value){ return { "myValidator": true }; } }

validate(c: Control): {[key: string]: any} { return this._validator(c); }}

Returns a StringMap<string, boolean> where the key is "error code" and the value is true if it fails

Page 30: Angular 2.0 forms

Custom Validator Assigning the Validator to the Control:

this.myForm = fb.group({ 'name': [

'', Validators.compose([

Validators.required , nameValidator

])]

});

and operation

Page 31: Angular 2.0 forms

Value Accessors

Page 32: Angular 2.0 forms

Interface ControlValueAccessor A bridge between a control and a native

element. A ControlValueAccessor abstracts the

operations of writing a new value to a DOM element representing an input control.

Page 33: Angular 2.0 forms

DefaultValueAccessor Directive The default accessor for writing a value and

listening to changes that is used by the: NgModel NgFormControl NgControlName

InputInput ModelDefaultValueAccessor Renderer On Change

ngModel | ngFormControl | ngControlName

Page 34: Angular 2.0 forms

DVA Code@Directive({ selector: 'input:not([type=checkbox])[ngControl],

textarea[ngControl],input:not([type=checkbox])[ngFormControl],textarea[ngFormControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]',

host: { '(input)': 'onChange($event.target.value)', '(blur)' : 'onTouched()'},

bindings: [DEFAULT_VALUE_ACCESSOR]}) export class DefaultValueAccessor implements ControlValueAccessor { onChange = (_) => {}; onTouched = () => {};

constructor(private _renderer:Renderer, private _elementRef:ElementRef) {}

writeValue(value: any): void { var normalizedValue = isBlank(value) ? '' : value; this._renderer.setElementProperty(

this._elementRef, 'value', normalizedValue); } registerOnChange(fn: (_: any) => void): void { this.onChange = fn; } registerOnTouched(fn: () => void): void { this.onTouched = fn; }}

Page 35: Angular 2.0 forms

setUpControl function This function are call when the

ngOnChanges in ngModel directive is call in the first time.

export function setUpControl( control: Control , dir: NgControl ): void {

...

dir.valueAccessor.writeValue(control.value);

// view -> model dir.valueAccessor.registerOnChange(newValue => { dir.viewToModelUpdate(newValue); control.updateValue(newValue, {emitModelToViewChange: false}); control.markAsDirty(); });

// model -> view control.registerOnChange(newValue => dir.valueAccessor.writeValue(newValue));

// touched dir.valueAccessor.registerOnTouched(() => control.markAsTouched());}

Page 36: Angular 2.0 forms

Form Classes

Page 37: Angular 2.0 forms

Resources Angular.io site (Developer guides - forms) Ng-Book 2 (

The Ultimate Guide to Forms in Angular 2 ) GitHub (Angular code source)

Page 38: Angular 2.0 forms

Thankseyalvardi.wordpress.com

Eyal Vardi

Site: http://ng-course.org

Blog: eyalVardi.wordpres.com