Form Directives (Template Driven)
'angular2/common'
import { FORM_DIRECTIVES } from 'angular2/common';
ngForm
ngFormModel
ngModel
ngControl
ngFormControl
Controls (Model Driven)
Validators
Accessors
Control
ControlGroup
ControlArray
 pristine
 dirty
 touched
 untouched
 errors
 valid
@Component({
selector: "search-comp",
directives: [FORM_DIRECTIVES],
template: `<input type='text' [(ngModel)]="name">`
})
class SearchComp {
name: string;
}
<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.
@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 */
}
<form #f="ngForm" (submit)='onLogIn(f.value)'>
Login <input type='text' ngControl='login' #l="ngForm">
<div *ngIf="!l.valid">Login is invalid</div>
</form>
Component
Field
Component Template Directive that in
use
name : string <input [(ngModel)]=“name” /> ngModel
name : string <input ngControl=“dName” [(ngModel)]=“name” /> ngControlName
 '[ngControl]'
 '[ngModel]:not([ngControl]):not([ngFormControl])'
This is still a
ngControl
Abstract
class
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
@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;
}
...
}
Track change-state
and validity
Validators
Control
My Component (model)
selector : '[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'],
<form #f="ngForm"
(ngSubmit)="onSubmit(f.value)">
</form>
ExportAs
Output
<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>
Directives Controls
ngFormModel ControlGroup | ControlArray
ngFormControl Control
export class App {
constructor() {
this.myForm = new ControlGroup({
myControl: new Control("")
});
}
}
<form [ngFormModel]="myForm">
<input ngFormControl="myControl">
</form>
constructor(builder: FormBuilder) {
this.loginForm = builder.group({
login: ["", Validators.required],
passwordRetry: builder.group({
password: ["", Validators.required],
pConfirmation: ["", Validators.required]
})
});
}
@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);
}
}
this.name.valueChanges.subscribe(
(value: string) => {
console.log('name changed to: ', value);
}
);
this.myForm.valueChanges.subscribe(
(value: string) => {
console.log('form changed to: ', value);
}
);
@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
this.myForm = fb.group({
'name': [
'',
Validators.compose([
Validators.required
, nameValidator
])
]
});
and operation
InputInput ModelDefaultValueAccessorRenderer On Change
@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; }
}
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());
}
Developer guides - forms
The Ultimate Guide to Forms in Angular 2
Angular code source
Angular 2.0 forms

Angular 2.0 forms