docs(forms): update and re-organize validation guide
This commit is contained in:

committed by
Victor Berchet

parent
5651e4ac72
commit
939dc44391
@ -3,10 +3,8 @@ import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
template: `<hero-form-template1></hero-form-template1>
|
||||
template: `<hero-form-template></hero-form-template>
|
||||
<hr>
|
||||
<hero-form-template2></hero-form-template2>
|
||||
<hr>
|
||||
<hero-form-reactive3></hero-form-reactive3>`
|
||||
<hero-form-reactive></hero-form-reactive>`
|
||||
})
|
||||
export class AppComponent { }
|
||||
|
@ -1,18 +1,26 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { HeroFormTemplateModule } from './template/hero-form-template.module';
|
||||
import { HeroFormReactiveModule } from './reactive/hero-form-reactive.module';
|
||||
import { HeroFormTemplateComponent } from './template/hero-form-template.component';
|
||||
import { HeroFormReactiveComponent } from './reactive/hero-form-reactive.component';
|
||||
import { ForbiddenValidatorDirective } from './shared/forbidden-name.directive';
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
HeroFormTemplateModule,
|
||||
HeroFormReactiveModule
|
||||
FormsModule,
|
||||
ReactiveFormsModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
HeroFormTemplateComponent,
|
||||
HeroFormReactiveComponent,
|
||||
ForbiddenValidatorDirective
|
||||
],
|
||||
declarations: [ AppComponent ],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
@ -1,26 +1,38 @@
|
||||
<!-- #docregion -->
|
||||
<div class="container">
|
||||
<div [hidden]="submitted">
|
||||
<h1>Hero Form 3 (Reactive)</h1>
|
||||
<!-- #docregion form-tag-->
|
||||
<form [formGroup]="heroForm" *ngIf="active" (ngSubmit)="onSubmit()">
|
||||
<!-- #enddocregion form-tag-->
|
||||
<div class="form-group">
|
||||
<!-- #docregion name-with-error-msg -->
|
||||
<label for="name">Name</label>
|
||||
|
||||
<input type="text" id="name" class="form-control"
|
||||
<h1>Reactive Form</h1>
|
||||
|
||||
<form [formGroup]="heroForm" #formDir="ngForm">
|
||||
|
||||
<div [hidden]="formDir.submitted">
|
||||
|
||||
<div class="form-group">
|
||||
|
||||
<label for="name">Name</label>
|
||||
<!-- #docregion name-with-error-msg -->
|
||||
<input id="name" class="form-control"
|
||||
formControlName="name" required >
|
||||
|
||||
<div *ngIf="formErrors.name" class="alert alert-danger">
|
||||
{{ formErrors.name }}
|
||||
<div *ngIf="name.invalid && (name.dirty || name.touched)"
|
||||
class="alert alert-danger">
|
||||
|
||||
<div *ngIf="name.errors.required">
|
||||
Name is required.
|
||||
</div>
|
||||
<div *ngIf="name.errors.minlength">
|
||||
Name must be at least 4 characters long.
|
||||
</div>
|
||||
<div *ngIf="name.errors.forbiddenName">
|
||||
Name cannot be Bob.
|
||||
</div>
|
||||
</div>
|
||||
<!-- #enddocregion name-with-error-msg -->
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input type="text" id="alterEgo" class="form-control"
|
||||
<input id="alterEgo" class="form-control"
|
||||
formControlName="alterEgo" >
|
||||
</div>
|
||||
|
||||
@ -31,17 +43,20 @@
|
||||
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
|
||||
<div *ngIf="formErrors.power" class="alert alert-danger">
|
||||
{{ formErrors.power }}
|
||||
<div *ngIf="power.invalid && power.touched" class="alert alert-danger">
|
||||
<div *ngIf="power.errors.required">Power is required.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-default"
|
||||
[disabled]="!heroForm.valid">Submit</button>
|
||||
[disabled]="heroForm.invalid">Submit</button>
|
||||
<button type="button" class="btn btn-default"
|
||||
(click)="addHero()">New Hero</button>
|
||||
</form>
|
||||
</div>
|
||||
(click)="formDir.resetForm({})">Reset</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<hero-submitted [hero]="hero" [(submitted)]="submitted"></hero-submitted>
|
||||
<div class="submitted-message" *ngIf="formDir.submitted">
|
||||
<p>You've submitted your hero, {{ heroForm.value.name }}!</p>
|
||||
<button (click)="formDir.resetForm({})">Add new hero</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,115 +2,39 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
import { Hero } from '../shared/hero';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { forbiddenNameValidator } from '../shared/forbidden-name.directive';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-form-reactive3',
|
||||
selector: 'hero-form-reactive',
|
||||
templateUrl: './hero-form-reactive.component.html'
|
||||
})
|
||||
export class HeroFormReactiveComponent implements OnInit {
|
||||
|
||||
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
|
||||
|
||||
hero = new Hero(18, 'Dr. WhatIsHisName', this.powers[0], 'Dr. What');
|
||||
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
|
||||
|
||||
submitted = false;
|
||||
|
||||
// #docregion on-submit
|
||||
onSubmit() {
|
||||
this.submitted = true;
|
||||
this.hero = this.heroForm.value;
|
||||
}
|
||||
// #enddocregion on-submit
|
||||
// #enddocregion
|
||||
|
||||
// Reset the form with a new hero AND restore 'pristine' class state
|
||||
// by toggling 'active' flag which causes the form
|
||||
// to be removed/re-added in a tick via NgIf
|
||||
// TODO: Workaround until NgForm has a reset method (#6822)
|
||||
active = true;
|
||||
// #docregion class
|
||||
// #docregion add-hero
|
||||
addHero() {
|
||||
this.hero = new Hero(42, '', '');
|
||||
this.buildForm();
|
||||
// #enddocregion add-hero
|
||||
// #enddocregion class
|
||||
|
||||
this.active = false;
|
||||
setTimeout(() => this.active = true, 0);
|
||||
// #docregion
|
||||
// #docregion add-hero
|
||||
}
|
||||
// #enddocregion add-hero
|
||||
|
||||
// #docregion form-builder
|
||||
heroForm: FormGroup;
|
||||
constructor(private fb: FormBuilder) { }
|
||||
|
||||
// #docregion form-group
|
||||
ngOnInit(): void {
|
||||
this.buildForm();
|
||||
}
|
||||
|
||||
buildForm(): void {
|
||||
this.heroForm = this.fb.group({
|
||||
// #docregion name-validators
|
||||
'name': [this.hero.name, [
|
||||
Validators.required,
|
||||
Validators.minLength(4),
|
||||
Validators.maxLength(24),
|
||||
forbiddenNameValidator(/bob/i)
|
||||
]
|
||||
],
|
||||
// #enddocregion name-validators
|
||||
'alterEgo': [this.hero.alterEgo],
|
||||
'power': [this.hero.power, Validators.required]
|
||||
// #docregion custom-validator
|
||||
this.heroForm = new FormGroup({
|
||||
'name': new FormControl(this.hero.name, [
|
||||
Validators.required,
|
||||
Validators.minLength(4),
|
||||
forbiddenNameValidator(/bob/i)
|
||||
]),
|
||||
'alterEgo': new FormControl(this.hero.alterEgo),
|
||||
'power': new FormControl(this.hero.power, Validators.required)
|
||||
});
|
||||
|
||||
this.heroForm.valueChanges
|
||||
.subscribe(data => this.onValueChanged(data));
|
||||
|
||||
this.onValueChanged(); // (re)set validation messages now
|
||||
// #enddocregion custom-validator
|
||||
}
|
||||
|
||||
// #enddocregion form-builder
|
||||
get name() { return this.heroForm.get('name'); }
|
||||
|
||||
onValueChanged(data?: any) {
|
||||
if (!this.heroForm) { return; }
|
||||
const form = this.heroForm;
|
||||
|
||||
for (const field in this.formErrors) {
|
||||
// clear previous error message (if any)
|
||||
this.formErrors[field] = '';
|
||||
const control = form.get(field);
|
||||
|
||||
if (control && control.dirty && !control.valid) {
|
||||
const messages = this.validationMessages[field];
|
||||
for (const key in control.errors) {
|
||||
this.formErrors[field] += messages[key] + ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
formErrors = {
|
||||
'name': '',
|
||||
'power': ''
|
||||
};
|
||||
|
||||
validationMessages = {
|
||||
'name': {
|
||||
'required': 'Name is required.',
|
||||
'minlength': 'Name must be at least 4 characters long.',
|
||||
'maxlength': 'Name cannot be more than 24 characters long.',
|
||||
'forbiddenName': 'Someone named "Bob" cannot be a hero.'
|
||||
},
|
||||
'power': {
|
||||
'required': 'Power is required.'
|
||||
}
|
||||
};
|
||||
get power() { return this.heroForm.get('power'); }
|
||||
// #enddocregion form-group
|
||||
}
|
||||
// #enddocregion
|
||||
|
@ -1,13 +0,0 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { HeroFormReactiveComponent } from './hero-form-reactive.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [ SharedModule, ReactiveFormsModule ],
|
||||
declarations: [ HeroFormReactiveComponent ],
|
||||
exports: [ HeroFormReactiveComponent ]
|
||||
})
|
||||
export class HeroFormReactiveModule { }
|
@ -6,9 +6,8 @@ import { AbstractControl, NG_VALIDATORS, Validator, ValidatorFn, Validators } fr
|
||||
/** A hero's name can't match the given regular expression */
|
||||
export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
|
||||
return (control: AbstractControl): {[key: string]: any} => {
|
||||
const name = control.value;
|
||||
const no = nameRe.test(name);
|
||||
return no ? {'forbiddenName': {name}} : null;
|
||||
const forbidden = nameRe.test(control.value);
|
||||
return forbidden ? {'forbiddenName': {value: control.value}} : null;
|
||||
};
|
||||
}
|
||||
// #enddocregion custom-validator
|
||||
|
@ -1,9 +0,0 @@
|
||||
// #docregion
|
||||
export class Hero {
|
||||
constructor(
|
||||
public id: number,
|
||||
public name: string,
|
||||
public power: string,
|
||||
public alterEgo?: string
|
||||
) { }
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { ForbiddenValidatorDirective } from './forbidden-name.directive';
|
||||
import { SubmittedComponent } from './submitted.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule],
|
||||
declarations: [ ForbiddenValidatorDirective, SubmittedComponent ],
|
||||
exports: [ ForbiddenValidatorDirective, SubmittedComponent,
|
||||
CommonModule ]
|
||||
})
|
||||
export class SharedModule { }
|
@ -1,32 +0,0 @@
|
||||
// #docregion
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
|
||||
import { Hero } from './hero';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-submitted',
|
||||
template: `
|
||||
<div *ngIf="submitted">
|
||||
<h2>You submitted the following:</h2>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">Name</div>
|
||||
<div class="col-xs-9 pull-left">{{ hero.name }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">Alter Ego</div>
|
||||
<div class="col-xs-9 pull-left">{{ hero.alterEgo }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">Power</div>
|
||||
<div class="col-xs-9 pull-left">{{ hero.power }}</div>
|
||||
</div>
|
||||
<br>
|
||||
<button class="btn btn-default" (click)="onClick()">Edit</button>
|
||||
</div>`
|
||||
})
|
||||
export class SubmittedComponent {
|
||||
@Input() hero: Hero;
|
||||
@Input() submitted = false;
|
||||
@Output() submittedChange = new EventEmitter<boolean>();
|
||||
onClick() { this.submittedChange.emit(false); }
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
<!-- #docregion -->
|
||||
<div class="container">
|
||||
|
||||
<h1>Template-Driven Form</h1>
|
||||
<!-- #docregion form-tag-->
|
||||
<form #heroForm="ngForm">
|
||||
<!-- #enddocregion form-tag-->
|
||||
<div [hidden]="heroForm.submitted">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<!-- #docregion name-with-error-msg -->
|
||||
<!-- #docregion name-input -->
|
||||
<input id="name" name="name" class="form-control"
|
||||
required minlength="4" forbiddenName="bob"
|
||||
[(ngModel)]="hero.name" #name="ngModel" >
|
||||
<!-- #enddocregion name-input -->
|
||||
|
||||
<div *ngIf="name.invalid && (name.dirty || name.touched)"
|
||||
class="alert alert-danger">
|
||||
|
||||
<div *ngIf="name.errors.required">
|
||||
Name is required.
|
||||
</div>
|
||||
<div *ngIf="name.errors.minlength">
|
||||
Name must be at least 4 characters long.
|
||||
</div>
|
||||
<div *ngIf="name.errors.forbiddenName">
|
||||
Name cannot be Bob.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- #enddocregion name-with-error-msg -->
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input id="alterEgo" class="form-control"
|
||||
name="alterEgo" [(ngModel)]="hero.alterEgo" >
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
<select id="power" name="power" class="form-control"
|
||||
required [(ngModel)]="hero.power" #power="ngModel" >
|
||||
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
|
||||
<div *ngIf="power.errors && power.touched" class="alert alert-danger">
|
||||
<div *ngIf="power.errors.required">Power is required.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-default"
|
||||
[disabled]="heroForm.invalid">Submit</button>
|
||||
<button type="button" class="btn btn-default"
|
||||
(click)="heroForm.resetForm({})">Reset</button>
|
||||
</div>
|
||||
|
||||
<div class="submitted-message" *ngIf="heroForm.submitted">
|
||||
<p>You've submitted your hero, {{ heroForm.value.name }}!</p>
|
||||
<button (click)="heroForm.resetForm({})">Add new hero</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
@ -0,0 +1,16 @@
|
||||
/* tslint:disable: member-ordering */
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-form-template',
|
||||
templateUrl: './hero-form-template.component.html'
|
||||
})
|
||||
export class HeroFormTemplateComponent {
|
||||
|
||||
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
|
||||
|
||||
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
|
||||
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { HeroFormTemplate1Component } from './hero-form-template1.component';
|
||||
import { HeroFormTemplate2Component } from './hero-form-template2.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [ SharedModule, FormsModule ],
|
||||
declarations: [ HeroFormTemplate1Component, HeroFormTemplate2Component ],
|
||||
exports: [ HeroFormTemplate1Component, HeroFormTemplate2Component ]
|
||||
})
|
||||
export class HeroFormTemplateModule { }
|
@ -1,61 +0,0 @@
|
||||
<!-- #docregion -->
|
||||
<div class="container">
|
||||
<div [hidden]="submitted">
|
||||
<h1>Hero Form 1 (Template)</h1>
|
||||
<!-- #docregion form-tag-->
|
||||
<form #heroForm="ngForm" *ngIf="active" (ngSubmit)="onSubmit()">
|
||||
<!-- #enddocregion form-tag-->
|
||||
<div class="form-group">
|
||||
<!-- #docregion name-with-error-msg -->
|
||||
<label for="name">Name</label>
|
||||
|
||||
<input type="text" id="name" class="form-control"
|
||||
required minlength="4" maxlength="24"
|
||||
name="name" [(ngModel)]="hero.name"
|
||||
#name="ngModel" >
|
||||
|
||||
<div *ngIf="name.errors && (name.dirty || name.touched)"
|
||||
class="alert alert-danger">
|
||||
<div [hidden]="!name.errors.required">
|
||||
Name is required
|
||||
</div>
|
||||
<div [hidden]="!name.errors.minlength">
|
||||
Name must be at least 4 characters long.
|
||||
</div>
|
||||
<div [hidden]="!name.errors.maxlength">
|
||||
Name cannot be more than 24 characters long.
|
||||
</div>
|
||||
</div>
|
||||
<!-- #enddocregion name-with-error-msg -->
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input type="text" id="alterEgo" class="form-control"
|
||||
name="alterEgo"
|
||||
[(ngModel)]="hero.alterEgo" >
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
<select id="power" class="form-control"
|
||||
name="power"
|
||||
[(ngModel)]="hero.power" required
|
||||
#power="ngModel" >
|
||||
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
|
||||
<div *ngIf="power.errors && power.touched" class="alert alert-danger">
|
||||
<div [hidden]="!power.errors.required">Power is required</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-default"
|
||||
[disabled]="!heroForm.form.valid">Submit</button>
|
||||
<button type="button" class="btn btn-default"
|
||||
(click)="addHero()">New Hero</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<hero-submitted [hero]="hero" [(submitted)]="submitted"></hero-submitted>
|
||||
</div>
|
@ -1,47 +0,0 @@
|
||||
/* tslint:disable: member-ordering */
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
|
||||
import { Hero } from '../shared/hero';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-form-template1',
|
||||
templateUrl: './hero-form-template1.component.html'
|
||||
})
|
||||
// #docregion class
|
||||
export class HeroFormTemplate1Component {
|
||||
|
||||
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
|
||||
|
||||
hero = new Hero(18, 'Dr. WhatIsHisWayTooLongName', this.powers[0], 'Dr. What');
|
||||
|
||||
submitted = false;
|
||||
|
||||
onSubmit() {
|
||||
this.submitted = true;
|
||||
}
|
||||
// #enddocregion class
|
||||
// #enddocregion
|
||||
// Reset the form with a new hero AND restore 'pristine' class state
|
||||
// by toggling 'active' flag which causes the form
|
||||
// to be removed/re-added in a tick via NgIf
|
||||
// TODO: Workaround until NgForm has a reset method (#6822)
|
||||
active = true;
|
||||
// #docregion
|
||||
// #docregion class
|
||||
|
||||
addHero() {
|
||||
this.hero = new Hero(42, '', '');
|
||||
// #enddocregion class
|
||||
// #enddocregion
|
||||
|
||||
this.active = false;
|
||||
setTimeout(() => this.active = true, 0);
|
||||
// #docregion
|
||||
// #docregion class
|
||||
}
|
||||
}
|
||||
// #enddocregion class
|
||||
// #enddocregion
|
@ -1,52 +0,0 @@
|
||||
<!-- #docregion -->
|
||||
<div class="container">
|
||||
<div [hidden]="submitted">
|
||||
<h1>Hero Form 2 (Template & Messages)</h1>
|
||||
<!-- #docregion form-tag-->
|
||||
<form #heroForm="ngForm" *ngIf="active" (ngSubmit)="onSubmit()">
|
||||
<!-- #enddocregion form-tag-->
|
||||
<div class="form-group">
|
||||
<!-- #docregion name-with-error-msg -->
|
||||
<label for="name">Name</label>
|
||||
|
||||
<!-- #docregion name-input -->
|
||||
<input type="text" id="name" class="form-control"
|
||||
required minlength="4" maxlength="24" forbiddenName="bob"
|
||||
name="name" [(ngModel)]="hero.name" >
|
||||
<!-- #enddocregion name-input -->
|
||||
|
||||
<div *ngIf="formErrors.name" class="alert alert-danger">
|
||||
{{ formErrors.name }}
|
||||
</div>
|
||||
<!-- #enddocregion name-with-error-msg -->
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input type="text" id="alterEgo" class="form-control"
|
||||
name="alterEgo"
|
||||
[(ngModel)]="hero.alterEgo" >
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
<select id="power" class="form-control"
|
||||
name="power"
|
||||
[(ngModel)]="hero.power" required >
|
||||
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
|
||||
<div *ngIf="formErrors.power" class="alert alert-danger">
|
||||
{{ formErrors.power }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-default"
|
||||
[disabled]="!heroForm.form.valid">Submit</button>
|
||||
<button type="button" class="btn btn-default"
|
||||
(click)="addHero()">New Hero</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<hero-submitted [hero]="hero" [(submitted)]="submitted"></hero-submitted>
|
||||
</div>
|
@ -1,99 +0,0 @@
|
||||
/* tslint:disable: member-ordering forin */
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { Component, AfterViewChecked, ViewChild } from '@angular/core';
|
||||
import { NgForm } from '@angular/forms';
|
||||
|
||||
import { Hero } from '../shared/hero';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-form-template2',
|
||||
templateUrl: './hero-form-template2.component.html'
|
||||
})
|
||||
export class HeroFormTemplate2Component implements AfterViewChecked {
|
||||
|
||||
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
|
||||
|
||||
hero = new Hero(18, 'Dr. WhatIsHisWayTooLongName', this.powers[0], 'Dr. What');
|
||||
|
||||
submitted = false;
|
||||
|
||||
onSubmit() {
|
||||
this.submitted = true;
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// Reset the form with a new hero AND restore 'pristine' class state
|
||||
// by toggling 'active' flag which causes the form
|
||||
// to be removed/re-added in a tick via NgIf
|
||||
// TODO: Workaround until NgForm has a reset method (#6822)
|
||||
active = true;
|
||||
// #docregion
|
||||
|
||||
addHero() {
|
||||
this.hero = new Hero(42, '', '');
|
||||
// #enddocregion
|
||||
|
||||
this.active = false;
|
||||
setTimeout(() => this.active = true, 0);
|
||||
// #docregion
|
||||
}
|
||||
|
||||
// #docregion view-child
|
||||
heroForm: NgForm;
|
||||
@ViewChild('heroForm') currentForm: NgForm;
|
||||
|
||||
ngAfterViewChecked() {
|
||||
this.formChanged();
|
||||
}
|
||||
|
||||
formChanged() {
|
||||
if (this.currentForm === this.heroForm) { return; }
|
||||
this.heroForm = this.currentForm;
|
||||
if (this.heroForm) {
|
||||
this.heroForm.valueChanges
|
||||
.subscribe(data => this.onValueChanged(data));
|
||||
}
|
||||
}
|
||||
// #enddocregion view-child
|
||||
|
||||
// #docregion handler
|
||||
onValueChanged(data?: any) {
|
||||
if (!this.heroForm) { return; }
|
||||
const form = this.heroForm.form;
|
||||
|
||||
for (const field in this.formErrors) {
|
||||
// clear previous error message (if any)
|
||||
this.formErrors[field] = '';
|
||||
const control = form.get(field);
|
||||
|
||||
if (control && control.dirty && !control.valid) {
|
||||
const messages = this.validationMessages[field];
|
||||
for (const key in control.errors) {
|
||||
this.formErrors[field] += messages[key] + ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
formErrors = {
|
||||
'name': '',
|
||||
'power': ''
|
||||
};
|
||||
// #enddocregion handler
|
||||
|
||||
// #docregion messages
|
||||
validationMessages = {
|
||||
'name': {
|
||||
'required': 'Name is required.',
|
||||
'minlength': 'Name must be at least 4 characters long.',
|
||||
'maxlength': 'Name cannot be more than 24 characters long.',
|
||||
'forbiddenName': 'Someone named "Bob" cannot be a hero.'
|
||||
},
|
||||
'power': {
|
||||
'required': 'Power is required.'
|
||||
}
|
||||
};
|
||||
// #enddocregion messages
|
||||
}
|
||||
// #enddocregion
|
Reference in New Issue
Block a user