diff --git a/packages/examples/forms/ts/formBuilder/form_builder_example.ts b/packages/examples/forms/ts/formBuilder/form_builder_example.ts
index e6fbd9c3eb..c71f8f0816 100644
--- a/packages/examples/forms/ts/formBuilder/form_builder_example.ts
+++ b/packages/examples/forms/ts/formBuilder/form_builder_example.ts
@@ -22,7 +22,7 @@ import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';
-
+
Value: {{ form.value | json }}
Validation status: {{ form.status }}
`
@@ -31,13 +31,15 @@ export class FormBuilderComp {
form: FormGroup;
constructor(@Inject(FormBuilder) fb: FormBuilder) {
- this.form = fb.group({
- name: fb.group({
- first: ['Nancy', Validators.minLength(2)],
- last: 'Drew',
- }),
- email: '',
- });
+ this.form = fb.group(
+ {
+ name: fb.group({
+ first: ['Nancy', Validators.minLength(2)],
+ last: 'Drew',
+ }),
+ email: '',
+ },
+ {updateOn: 'change'});
}
}
// #enddocregion
@@ -56,4 +58,4 @@ export class DisabledFormControlComponent {
this.control = fb.control({value: 'my val', disabled: true});
}
}
-// #enddocregion disabled-control
\ No newline at end of file
+// #enddocregion disabled-control
diff --git a/packages/forms/src/form_builder.ts b/packages/forms/src/form_builder.ts
index dc4825c3f9..3e611c55d1 100644
--- a/packages/forms/src/form_builder.ts
+++ b/packages/forms/src/form_builder.ts
@@ -9,7 +9,7 @@
import {Injectable} from '@angular/core';
import {AsyncValidatorFn, ValidatorFn} from './directives/validators';
-import {AbstractControl, FormArray, FormControl, FormGroup} from './model';
+import {AbstractControl, AbstractControlOptions, FormArray, FormControl, FormGroup, FormHooks} from './model';
/**
* @description
@@ -37,25 +37,43 @@ export class FormBuilder {
* * `asyncValidator`: A single async validator or array of async validator functions
*
*/
- group(controlsConfig: {[key: string]: any}, extra: {[key: string]: any}|null = null): FormGroup {
+ group(controlsConfig: {[key: string]: any}, legacyOrOpts: {[key: string]: any}|null = null):
+ FormGroup {
const controls = this._reduceControls(controlsConfig);
- const validator: ValidatorFn = extra != null ? extra['validator'] : null;
- const asyncValidator: AsyncValidatorFn = extra != null ? extra['asyncValidator'] : null;
- return new FormGroup(controls, validator, asyncValidator);
+
+ let validators: ValidatorFn|ValidatorFn[]|null = null;
+ let asyncValidators: AsyncValidatorFn|AsyncValidatorFn[]|null = null;
+ let updateOn: FormHooks|undefined = undefined;
+
+ if (legacyOrOpts != null &&
+ (legacyOrOpts.asyncValidator !== undefined || legacyOrOpts.validator !== undefined)) {
+ // `legacyOrOpts` are legacy form group options
+ validators = legacyOrOpts.validator != null ? legacyOrOpts.validator : null;
+ asyncValidators = legacyOrOpts.asyncValidator != null ? legacyOrOpts.asyncValidator : null;
+ } else if (legacyOrOpts != null) {
+ // `legacyOrOpts` are `AbstractControlOptions`
+ validators = legacyOrOpts.validators != null ? legacyOrOpts.validators : null;
+ asyncValidators = legacyOrOpts.asyncValidators != null ? legacyOrOpts.asyncValidators : null;
+ updateOn = legacyOrOpts.updateOn != null ? legacyOrOpts.updateOn : undefined;
+ }
+
+ return new FormGroup(controls, {asyncValidators, updateOn, validators});
}
/**
* @description
- * Construct a new `FormControl` instance.
+ * Construct a new `FormControl` with the given state, validators and options.
*
- * @param formState Initializes the control with an initial value,
- * or an object that defines the initial value and disabled state.
+ * @param formState Initializes the control with an initial state value, or
+ * with an object that contains both a value and a disabled status.
*
- * @param validator A synchronous validator function, or an array of synchronous validator
+ * @param validatorOrOpts A synchronous validator function, or an array of
+ * such functions, or an `AbstractControlOptions` object that contains
+ * validation functions and a validation trigger.
+ *
+ * @param asyncValidator A single async validator or array of async validator
* functions.
*
- * @param asyncValidator A single async validator or array of async validator functions
- *
* @usageNotes
*
* ### Initialize a control as disabled
@@ -65,31 +83,33 @@ export class FormBuilder {
*
*
- *
*/
control(
- formState: any, validator?: ValidatorFn|ValidatorFn[]|null,
+ formState: any, validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null,
asyncValidator?: AsyncValidatorFn|AsyncValidatorFn[]|null): FormControl {
- return new FormControl(formState, validator, asyncValidator);
+ return new FormControl(formState, validatorOrOpts, asyncValidator);
}
/**
- * @description
- * Construct a new `FormArray` instance.
+ * Constructs a new `FormArray` from the given array of configurations,
+ * validators and options.
*
- * @param controlsConfig An array of child controls. The key for each child control is its index
- * in the array.
+ * @param controlsConfig An array of child controls or control configs. Each
+ * child control is given an index when it is registered.
*
- * @param validator A synchronous validator function, or an array of synchronous validator
+ * @param validatorOrOpts A synchronous validator function, or an array of
+ * such functions, or an `AbstractControlOptions` object that contains
+ * validation functions and a validation trigger.
+ *
+ * @param asyncValidator A single async validator or array of async validator
* functions.
- *
- * @param asyncValidator A single async validator or array of async validator functions
*/
array(
- controlsConfig: any[], validator?: ValidatorFn|ValidatorFn[]|null,
+ controlsConfig: any[],
+ validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null,
asyncValidator?: AsyncValidatorFn|AsyncValidatorFn[]|null): FormArray {
const controls = controlsConfig.map(c => this._createControl(c));
- return new FormArray(controls, validator, asyncValidator);
+ return new FormArray(controls, validatorOrOpts, asyncValidator);
}
/** @internal */
diff --git a/packages/forms/test/form_builder_spec.ts b/packages/forms/test/form_builder_spec.ts
index bf7596eade..e04cd74677 100644
--- a/packages/forms/test/form_builder_spec.ts
+++ b/packages/forms/test/form_builder_spec.ts
@@ -7,7 +7,7 @@
*/
import {fakeAsync, tick} from '@angular/core/testing';
import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testing_internal';
-import {FormBuilder} from '@angular/forms';
+import {FormBuilder, Validators} from '@angular/forms';
import {of } from 'rxjs';
(function() {
@@ -119,5 +119,84 @@ import {of } from 'rxjs';
expect(a.value).toEqual(['one', 'two']);
expect(a.errors).toEqual({'sync1': true, 'sync2': true});
});
+
+ describe('updateOn', () => {
+ it('should default to on change', () => {
+ const c = b.control('');
+ expect(c.updateOn).toEqual('change');
+ });
+
+ it('should default to on change with an options obj', () => {
+ const c = b.control('', {validators: Validators.required});
+ expect(c.updateOn).toEqual('change');
+ });
+
+ it('should set updateOn when updating on blur', () => {
+ const c = b.control('', {updateOn: 'blur'});
+ expect(c.updateOn).toEqual('blur');
+ });
+
+ describe('in groups and arrays', () => {
+ it('should default to group updateOn when not set in control', () => {
+ const g = b.group({one: b.control(''), two: b.control('')}, {updateOn: 'blur'});
+
+ expect(g.get('one') !.updateOn).toEqual('blur');
+ expect(g.get('two') !.updateOn).toEqual('blur');
+ });
+
+ it('should default to array updateOn when not set in control', () => {
+ const a = b.array([b.control(''), b.control('')], {updateOn: 'blur'});
+
+ expect(a.get([0]) !.updateOn).toEqual('blur');
+ expect(a.get([1]) !.updateOn).toEqual('blur');
+ });
+
+ it('should set updateOn with nested groups', () => {
+ const g = b.group(
+ {
+ group: b.group({one: b.control(''), two: b.control('')}),
+ },
+ {updateOn: 'blur'});
+
+ expect(g.get('group.one') !.updateOn).toEqual('blur');
+ expect(g.get('group.two') !.updateOn).toEqual('blur');
+ expect(g.get('group') !.updateOn).toEqual('blur');
+ });
+
+ it('should set updateOn with nested arrays', () => {
+ const g = b.group(
+ {
+ arr: b.array([b.control(''), b.control('')]),
+ },
+ {updateOn: 'blur'});
+
+ expect(g.get(['arr', 0]) !.updateOn).toEqual('blur');
+ expect(g.get(['arr', 1]) !.updateOn).toEqual('blur');
+ expect(g.get('arr') !.updateOn).toEqual('blur');
+ });
+
+ it('should allow control updateOn to override group updateOn', () => {
+ const g = b.group(
+ {one: b.control('', {updateOn: 'change'}), two: b.control('')}, {updateOn: 'blur'});
+
+ expect(g.get('one') !.updateOn).toEqual('change');
+ expect(g.get('two') !.updateOn).toEqual('blur');
+ });
+
+ it('should set updateOn with complex setup', () => {
+ const g = b.group({
+ group: b.group(
+ {one: b.control('', {updateOn: 'change'}), two: b.control('')}, {updateOn: 'blur'}),
+ groupTwo: b.group({one: b.control('')}, {updateOn: 'submit'}),
+ three: b.control('')
+ });
+
+ expect(g.get('group.one') !.updateOn).toEqual('change');
+ expect(g.get('group.two') !.updateOn).toEqual('blur');
+ expect(g.get('groupTwo.one') !.updateOn).toEqual('submit');
+ expect(g.get('three') !.updateOn).toEqual('change');
+ });
+ });
+ });
});
})();
diff --git a/tools/public_api_guard/forms/forms.d.ts b/tools/public_api_guard/forms/forms.d.ts
index 1406341355..8744ac8a96 100644
--- a/tools/public_api_guard/forms/forms.d.ts
+++ b/tools/public_api_guard/forms/forms.d.ts
@@ -201,11 +201,11 @@ export declare class FormArrayName extends ControlContainer implements OnInit, O
}
export declare class FormBuilder {
- array(controlsConfig: any[], validator?: ValidatorFn | ValidatorFn[] | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null): FormArray;
- control(formState: any, validator?: ValidatorFn | ValidatorFn[] | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null): FormControl;
+ array(controlsConfig: any[], validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null): FormArray;
+ control(formState: any, validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null): FormControl;
group(controlsConfig: {
[key: string]: any;
- }, extra?: {
+ }, legacyOrOpts?: {
[key: string]: any;
} | null): FormGroup;
}