Created by Dariusz Biedrzycki / kontakt@3wm.pl / Mobiem.pl
Two way data binding
<input
type="text"
[(ngModel)]="user.login"
name="login"
/>
initData(){
this.user = { login:"" };
}
<button
(click)="saveData()"
>
Register
</button>
saveData(){
if(this.validateData(this.user)){
this.registerApi.save(this.user);
}
}
<form
(ngSubmit)="saveData()"
/>
<input
type="submit"
value="Register"
/>
</form>
saveData(){
if(this.validateData(this.user)){
this.registerApi.save(this.user);
}
}
<input
type="text"
/>
<p
*ngIf="loginError"
>{{loginError}} </p>
saveData(){
if(this.validateData(this.user)){
this.registerApi.save(this.user);
} else {
this.showErrors();
}
}
<input
type="text"
(ngChange)="validateLogin()"
/>
<p
*ngIf="loginError"
>{{loginError}} </p>
validateLogin(){
}
Old way
Dowoloność implementacji
Two way data binding
Zmiana modelu w wielu miejscach
Two way data binding
src/app/app.module.ts
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [
...
FormsModule,
...
],
...
})
export class AppModule { }
src/app/register.component.html
<form
(onSubmit)="onSubmit(f)"
#f
>
<input
type="text"
ngModel
name="userLogin"
/>
<button type="submit"> Register </button>
</form>
src/app/register.component.ts
...
onSubmit(form) {
console.log(form);
}
...
src/app/register.component.html
<form
(onSubmit)="onSubmit(f)"
#f
>
src/app/register.component.ts
...
onSubmit(form:HTMLFormElement) {
console.log(form);
}
...
src/app/register.component.html
<form
(onSubmit)="onSubmit(f)"
#f="ngForm"
>
<input
type="text"
ngModel
name="userLogin"
/>
<button type="submit"> Register </button>
</form>
src/app/register.component.ts
import {NgForm} from "@angular/forms";
...
onSubmit(form: NgForm) {
console.log(form);
}
...
{
controls: {
userLogin: {
dirty: false,
pristine: true,
invalid: false
valid: true
touched: false
untouched: true
}
}
value: {
userLogin: "to co wpisaliśmy"
},
dirty: false...
}
src/app/register.component.html
<form
(onSubmit)="onSubmit()"
#f="ngForm"
>
src/app/register.component.ts
import {Component, ViewChild} from '@angular/core';
...
@ViewChild('f') registerForm: NgForm;
...
onSubmit() {
console.log(this.registerForm);
if(this.registerForm.valid){
this.registerApi.save(this.registerForm.value);
}
}
...
touched
ng-touched
ng-untouched
dirty
ng-dirty
ng-pristine
valid
ng-valid
ng-invalid
src/app/register.component.html
<form (onSubmit)="onSubmit(f)" #f="ngForm">
<input
type="text"
ngModel
name="userLogin"
required
forbiddenName="bob"
/>
<button type="submit"> Register </button>
</form>
Wbudowane walidatory
class Validators {
static min(min: number): ValidatorFn
static max(max: number): ValidatorFn
static required(control: AbstractControl): ValidationErrors|null
static requiredTrue(control: AbstractControl): ValidationErrors|null
static email(control: AbstractControl): ValidationErrors|null
static minLength(minLength: number): ValidatorFn
static maxLength(maxLength: number): ValidatorFn
static pattern(pattern: string|RegExp): ValidatorFn
static nullValidator(c: AbstractControl): ValidationErrors|null
static compose(validators: (ValidatorFn|null|undefined)[]|null): ValidatorFn|null
static composeAsync(validators: (AsyncValidatorFn|null)[]): AsyncValidatorFn|null
}
src/app/forbidden-name.directive.ts
export function
forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
const forbidden = nameRe.test(control.value);
return forbidden ? {
'forbiddenName': {value: control.value}} : null;
};
}
https://angular.io/generated/live-examples/form-validation/eplnkr.html
src/app/register.comonent.css
.ng-valid[required], .ng-valid.required {
border-left: 5px solid #42A948; /* green */
}
.ng-invalid:not(form) {
border-left: 5px solid #a94442; /* red */
}
Template driven
Prostota
Może pisać kto inny niż programista angular
Więcej walidatorów, spada czytelność
Brak możliwości testowania przez unit testy
src/app/app.module.ts
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [
...
ReactiveFormsModule,
...
],
...
})
export class AppModule { }
src/app/register.component.html
<form
[formGroup]="registerForm" (submit)="onSubmit()"
>
<input
type="text"
formControlName="userLogin"
/>
<button type="submit"> Register </button>
</form>
src/app/register.component.ts
import { FormGroup, FormControl} from '@angular/forms';
...
registerForm:FormGroup;
...
initForm(){
this.registerForm = new FormGroup({
userLogin: new FormControl(null)
});
}
...
src/app/register.component.html
<form [formGroup]="registerForm" (submit)="onSubmit()">
<input
type="text"
formControlName="userLogin"
/>
<button type="submit"> Register </button>
</form>
src/app/register.component.ts
...
initForm(){
this.registerForm = new FormGroup({
userLogin: new FormControl(null)
});
}
...
onSubmit() {
console.log(this.registerForm);
}
{
controls: {
userLogin: {
dirty: false,
pristine: true,
invalid: false
valid: true
touched: false
untouched: true
}
}
value: {
userLogin: "to co wpisaliśmy"
},
dirty: false...
}
src/app/register.component.html
<form [formGroup]="registerForm" (submit)="onSubmit()">
<input type="text"
formControlName="userLogin"
/>
<button type="submit"> Register </button>
</form>
src/app/register.component.ts
import { FormGroup, FormControl, Validators}
from '@angular/forms';
...
registerForm:FormGroup;
initForm(){
this.registerForm = new FormGroup({
userLogin: new FormControl('Janusz', [
Validators.required,
this.properName.bind(this)
])
});
}
...
src/app/register.component.ts
properName(control: FormControl): {[s:string]: boolean}{
if (control.value == 'JanuszBiznesu') {
return null;
} else {
return {'properName': true}
}
}
{
controls: {
userLogin: {
errors: {
properName: true
}
}
}
value: {
userLogin: "to co wpisaliśmy"
},
dirty: false...
}
src/app/register.component.html
<form [formGroup]="registerForm" (submit)="onSubmit()">
<input type="text" formControlName="userLogin" />
<div
*ngIf="
registerForm.get('userLogin').errors &&
registerForm.get('userLogin').touched"
>
<span *ngIf="registerForm.get('userLogin').errors.properName">
Prawidłowa nazwa użytkownika to JanuszBiznesu
</span>
</div>
<button type="submit"> Register </button>
</form>
src/app/register.component.ts
import { FormGroup, FormControl, Validators}
from '@angular/forms';
...
registerForm:FormGroup;
initForm(){
this.registerForm = new FormGroup({
adress: new FormGroup({
home: new FormControl(null, Validators.required),
work: new FormControl(null, Validators.required)
})
});
}
...
src/app/register.component.ts
import { FormGroup, FormControl, Validators, FormArray}
from '@angular/forms';
initForm(){
this.registerForm = new FormGroup({
hobby: new FormArray([])
});
}
addHobby(){
(<FormArray>registerForm.get('hobby'))
.push(
new FormControl(null, Validators.required)
)
}
src/app/register.component.ts
initForm(){
this.registerForm = new FormGroup({
userLogin: new FormControl(null)
});
this.registerForm.valueChanges.subscribe((value)=>{
//{
// userLogin: "to co wpisaliśmy"
//}
});
this.registerForm.statusChanges.subscribe((value)=>{
//INVALID i VALID
});
}
src/app/register.component.ts
this.registerForm = new FormGroup({
userLogin: new FormControl(null),
hobby: new FormArray([]),
adress: new FormGroup({
home: new FormControl(null, Validators.required),
work: new FormControl(null, Validators.required)
})
});
this.registerForm.setValue({
'userLogin': "Jan"
'hobby': ['szachy'],
'addres': {'work':"Warszawa", 'home':"Płock"}
});
src/app/register.component.ts
this.registerForm = new FormGroup({
userLogin: new FormControl(null),
hobby: new FormArray([]),
adress: new FormGroup({
home: new FormControl(null, Validators.required),
work: new FormControl(null, Validators.required)
})
});
this.registerForm.patchValue({
'userLogin': "Roman"
});
Reactive Way
Możliwe unit testy logiki validacji
Szablony bez logiki
Pełna kontrola nad modelem fomularza
Więcej pisania
src/app/register.component.ts
this.registerForm.valueChanges
.map((value) => {
value.userLogin = value.userLogin.toUpperCase();
return value;
})
.filter((value) => this.form.valid)
.subscribe((value) => {
console.log("Model Driven Form valid value: vm = ",
JSON.stringify(value));
});
Dariusz Biedrzycki
kontakt@3wm.pl
Mobiem.pl