Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions aio/content/examples/form-validation/e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,50 @@ describe('Form Validation Tests', function () {
tests('Reactive Form');
bobTests();
});

describe('UpdateOn form', () => {
let updatePage: {
select: ElementFinder,
input: ElementFinder,
changeOption: ElementFinder,
nameText: ElementFinder,
statusText: ElementFinder
};

beforeEach(() => {
const section = element(by.css('hero-form-update-on'));
updatePage = {
select: section.element(by.css('select')),
input: section.element(by.css('input')),
changeOption: section.element(by.css('option')),
nameText: section.element(by.id('nameText')),
statusText: section.element(by.id('statusText'))
};
});

it('should default to updateOn: blur', () => {
expect(updatePage.select.getAttribute('value')).toEqual('blur');
});

it('should not update value/validity until blur', () => {
updatePage.input.sendKeys('Nancy');
expect(updatePage.nameText.getText()).toEqual('');
expect(updatePage.statusText.getText()).toEqual('INVALID');
updatePage.nameText.click();
expect(updatePage.nameText.getText()).toEqual('Nancy');
expect(updatePage.statusText.getText()).toEqual('VALID');
});

it('should update on change when selected', () => {
updatePage.select.click();
updatePage.changeOption.click();

updatePage.input.sendKeys('Nancy');
expect(updatePage.nameText.getText()).toEqual('Nancy');
expect(updatePage.statusText.getText()).toEqual('VALID');
});

});
});

//////////
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { Component } from '@angular/core';
selector: 'my-app',
template: `<hero-form-template></hero-form-template>
<hr>
<hero-form-reactive></hero-form-reactive>`
<hero-form-reactive></hero-form-reactive>
<hr>
<hero-form-update-on></hero-form-update-on>`
})
export class AppComponent { }
4 changes: 3 additions & 1 deletion aio/content/examples/form-validation/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HeroFormTemplateComponent } from './template/hero-form-template.component';
import { HeroFormReactiveComponent } from './reactive/hero-form-reactive.component';
import { HeroFormUpdateOnComponent } from './reactive/hero-form-update-on.component';
import { ForbiddenValidatorDirective } from './shared/forbidden-name.directive';


Expand All @@ -19,7 +20,8 @@ import { ForbiddenValidatorDirective } from './shared/forbidden-name.directive';
AppComponent,
HeroFormTemplateComponent,
HeroFormReactiveComponent,
ForbiddenValidatorDirective
HeroFormUpdateOnComponent,
ForbiddenValidatorDirective,
],
bootstrap: [ AppComponent ]
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!-- #docregion -->
<div class="container">

<h1>UpdateOn Demo</h1>

<div class="form-group">
<label for="updateOn">Currently updating name on: </label>
<select id="updateOn" class="form-control" [formControl]="updateOnControl">
<option value="change">change</option>
<option value="blur">blur</option>
</select>
</div>

<form [formGroup]="form">
<div class="form-group">
<label for="updateOnName">Name</label>

<input id="updateOnName" class="form-control"
formControlName="name" required>

<div style="margin: 16px 0">
<p id="nameText"> Your hero's name is: {{ name.value }} </p>
<p id="statusText"> This name is considered: {{ name.status }} </p>
</div>

</div>
</form>
</div>
<!-- #enddocregion -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* tslint:disable: member-ordering forin */
// #docplaster
// #docregion
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';

@Component({
selector: 'hero-form-update-on',
templateUrl: './hero-form-update-on.component.html'
})
export class HeroFormUpdateOnComponent implements OnInit, OnDestroy {
// #docregion updateon
form = new FormGroup({
name: new FormControl('', {
validators: Validators.required,
updateOn: 'blur'
})
});
// #enddocregion updateon

updateOnControl = new FormControl('blur');
updateOnSub: any;

ngOnInit() {
// To support changing the updateOn configuration in the demo,
// we set up a new FormControl when the updateOn value changes.
this.updateOnSub = this.updateOnControl.valueChanges.subscribe(value => {
this.form.setControl('name', new FormControl(this.name.value, {
validators: Validators.required,
updateOn: value
}));
});
}

ngOnDestroy() {
this.updateOnSub.unsubscribe();
}

get name() { return this.form.get('name'); }

}
// #enddocregion
14 changes: 14 additions & 0 deletions aio/content/guide/form-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@ Key takeaways:
* The `required` attribute is still present. While it's not necessary for validation purposes,
you may want to keep it in your template for CSS styling or accessibility reasons.

### Validation timing

By default, the value and validation status of a `FormControl` updates whenever its value changes. If your application
has heavy validation requirements, you may not want to run validation this often. Using reactive forms,
it's possible to delay the process until the user has blurred the input.

To set this up, set the `updateOn` option when instantiating your `FormControl`. In the below example, it's
set to `'blur'`, so no changes to value or validation status will occur until the blur event occurs.

<code-example path="form-validation/src/app/reactive/hero-form-update-on.component.ts" region="updateon" title="reactive/hero-form-update-on.component.ts (update-on)">
</code-example>

Like in AngularJS, setting `updateOn` to `'blur'` will delay the update of the value as well as the validation status. Updating
value and validity together keeps the system easy to reason about, as the two will always be in sync.

## Custom validators

Expand Down