angular-cn/modules/@angular/forms/src/model.ts

772 lines
24 KiB
TypeScript
Raw Normal View History

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {BaseException} from '@angular/core';
import {PromiseObservable} from 'rxjs/observable/PromiseObservable';
import {composeAsyncValidators, composeValidators} from './directives/shared';
import {AsyncValidatorFn, ValidatorFn} from './directives/validators';
import {EventEmitter, Observable} from './facade/async';
import {ListWrapper, StringMapWrapper} from './facade/collection';
2016-06-20 13:55:29 -04:00
import {isBlank, isPresent, isPromise, normalizeBool} from './facade/lang';
2016-06-08 18:36:24 -04:00
/**
* Indicates that a FormControl is valid, i.e. that no errors exist in the input value.
2016-06-08 18:36:24 -04:00
*/
export const VALID = 'VALID';
2016-06-08 18:36:24 -04:00
/**
* Indicates that a FormControl is invalid, i.e. that an error exists in the input value.
2016-06-08 18:36:24 -04:00
*/
export const INVALID = 'INVALID';
2016-06-08 18:36:24 -04:00
/**
* Indicates that a FormControl is pending, i.e. that async validation is occurring and
2016-06-08 18:36:24 -04:00
* errors are not yet available for the input value.
*/
export const PENDING = 'PENDING';
2016-06-08 18:36:24 -04:00
export function isControl(control: Object): boolean {
return control instanceof AbstractControl;
}
function _find(control: AbstractControl, path: Array<string|number>| string, delimiter: string) {
2016-06-08 18:36:24 -04:00
if (isBlank(path)) return null;
if (!(path instanceof Array)) {
path = (<string>path).split(delimiter);
2016-06-08 18:36:24 -04:00
}
if (path instanceof Array && ListWrapper.isEmpty(path)) return null;
return (<Array<string|number>>path).reduce((v, name) => {
if (v instanceof FormGroup) {
return isPresent(v.controls[name]) ? v.controls[name] : null;
} else if (v instanceof FormArray) {
var index = <number>name;
return isPresent(v.at(index)) ? v.at(index) : null;
} else {
return null;
}
}, control);
2016-06-08 18:36:24 -04:00
}
function toObservable(r: any): Observable<any> {
return isPromise(r) ? PromiseObservable.create(r) : r;
2016-06-08 18:36:24 -04:00
}
function coerceToValidator(validator: ValidatorFn | ValidatorFn[]): ValidatorFn {
return Array.isArray(validator) ? composeValidators(validator) : validator;
}
function coerceToAsyncValidator(asyncValidator: AsyncValidatorFn | AsyncValidatorFn[]):
AsyncValidatorFn {
return Array.isArray(asyncValidator) ? composeAsyncValidators(asyncValidator) : asyncValidator;
}
2016-06-08 18:36:24 -04:00
/**
* @stable
2016-06-08 18:36:24 -04:00
*/
export abstract class AbstractControl {
/** @internal */
_value: any;
private _valueChanges: EventEmitter<any>;
private _statusChanges: EventEmitter<any>;
private _status: string;
private _errors: {[key: string]: any};
private _pristine: boolean = true;
private _touched: boolean = false;
private _parent: FormGroup|FormArray;
2016-06-08 18:36:24 -04:00
private _asyncValidationSubscription: any;
constructor(public validator: ValidatorFn, public asyncValidator: AsyncValidatorFn) {}
get value(): any { return this._value; }
get status(): string { return this._status; }
get valid(): boolean { return this._status === VALID; }
get invalid(): boolean { return this._status === INVALID; }
2016-06-08 18:36:24 -04:00
/**
* Returns the errors of this control.
*/
get errors(): {[key: string]: any} { return this._errors; }
get pristine(): boolean { return this._pristine; }
get dirty(): boolean { return !this.pristine; }
get touched(): boolean { return this._touched; }
get untouched(): boolean { return !this._touched; }
get valueChanges(): Observable<any> { return this._valueChanges; }
get statusChanges(): Observable<any> { return this._statusChanges; }
get pending(): boolean { return this._status == PENDING; }
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]): void {
this.asyncValidator = coerceToAsyncValidator(newValidator);
}
clearAsyncValidators(): void { this.asyncValidator = null; }
setValidators(newValidator: ValidatorFn|ValidatorFn[]): void {
this.validator = coerceToValidator(newValidator);
}
clearValidators(): void { this.validator = null; }
markAsTouched({onlySelf}: {onlySelf?: boolean} = {}): void {
onlySelf = normalizeBool(onlySelf);
this._touched = true;
if (isPresent(this._parent) && !onlySelf) {
this._parent.markAsTouched({onlySelf: onlySelf});
}
}
2016-06-08 18:36:24 -04:00
markAsDirty({onlySelf}: {onlySelf?: boolean} = {}): void {
onlySelf = normalizeBool(onlySelf);
this._pristine = false;
if (isPresent(this._parent) && !onlySelf) {
this._parent.markAsDirty({onlySelf: onlySelf});
}
}
markAsPristine({onlySelf}: {onlySelf?: boolean} = {}): void {
this._pristine = true;
this._forEachChild((control: AbstractControl) => { control.markAsPristine({onlySelf: true}); });
if (isPresent(this._parent) && !onlySelf) {
this._parent._updatePristine({onlySelf: onlySelf});
}
}
markAsUntouched({onlySelf}: {onlySelf?: boolean} = {}): void {
this._touched = false;
this._forEachChild(
(control: AbstractControl) => { control.markAsUntouched({onlySelf: true}); });
if (isPresent(this._parent) && !onlySelf) {
this._parent._updateTouched({onlySelf: onlySelf});
}
}
2016-06-08 18:36:24 -04:00
markAsPending({onlySelf}: {onlySelf?: boolean} = {}): void {
onlySelf = normalizeBool(onlySelf);
this._status = PENDING;
if (isPresent(this._parent) && !onlySelf) {
this._parent.markAsPending({onlySelf: onlySelf});
}
}
setParent(parent: FormGroup|FormArray): void { this._parent = parent; }
2016-06-08 18:36:24 -04:00
abstract setValue(value: any, options?: Object): void;
abstract patchValue(value: any, options?: Object): void;
abstract reset(value?: any, options?: Object): void;
updateValueAndValidity({onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}):
void {
2016-06-08 18:36:24 -04:00
onlySelf = normalizeBool(onlySelf);
emitEvent = isPresent(emitEvent) ? emitEvent : true;
this._updateValue();
this._errors = this._runValidator();
this._status = this._calculateStatus();
if (this._status == VALID || this._status == PENDING) {
this._runAsyncValidator(emitEvent);
}
if (emitEvent) {
this._valueChanges.emit(this._value);
this._statusChanges.emit(this._status);
2016-06-08 18:36:24 -04:00
}
if (isPresent(this._parent) && !onlySelf) {
this._parent.updateValueAndValidity({onlySelf: onlySelf, emitEvent: emitEvent});
}
}
private _runValidator(): {[key: string]: any} {
return isPresent(this.validator) ? this.validator(this) : null;
}
private _runAsyncValidator(emitEvent: boolean): void {
if (isPresent(this.asyncValidator)) {
this._status = PENDING;
this._cancelExistingSubscription();
var obs = toObservable(this.asyncValidator(this));
this._asyncValidationSubscription = obs.subscribe(
{next: (res: {[key: string]: any}) => this.setErrors(res, {emitEvent: emitEvent})});
2016-06-08 18:36:24 -04:00
}
}
private _cancelExistingSubscription(): void {
if (isPresent(this._asyncValidationSubscription)) {
this._asyncValidationSubscription.unsubscribe();
2016-06-08 18:36:24 -04:00
}
}
/**
* Sets errors on a form control.
2016-06-08 18:36:24 -04:00
*
* This is used when validations are run not automatically, but manually by the user.
*
* Calling `setErrors` will also update the validity of the parent control.
*
* ## Usage
*
* ```
* var login = new FormControl("someLogin");
2016-06-08 18:36:24 -04:00
* login.setErrors({
* "notUnique": true
* });
*
* expect(login.valid).toEqual(false);
* expect(login.errors).toEqual({"notUnique": true});
*
* login.updateValue("someOtherLogin");
*
* expect(login.valid).toEqual(true);
* ```
*/
setErrors(errors: {[key: string]: any}, {emitEvent}: {emitEvent?: boolean} = {}): void {
emitEvent = isPresent(emitEvent) ? emitEvent : true;
this._errors = errors;
this._updateControlsErrors(emitEvent);
2016-06-08 18:36:24 -04:00
}
get(path: Array<string|number>|string): AbstractControl { return _find(this, path, '.'); }
2016-06-08 18:36:24 -04:00
getError(errorCode: string, path: string[] = null): any {
var control = isPresent(path) && !ListWrapper.isEmpty(path) ? this.get(path) : this;
2016-06-08 18:36:24 -04:00
if (isPresent(control) && isPresent(control._errors)) {
return StringMapWrapper.get(control._errors, errorCode);
} else {
return null;
}
}
hasError(errorCode: string, path: string[] = null): boolean {
return isPresent(this.getError(errorCode, path));
}
get root(): AbstractControl {
let x: AbstractControl = this;
while (isPresent(x._parent)) {
x = x._parent;
}
return x;
}
/** @internal */
_updateControlsErrors(emitEvent: boolean): void {
2016-06-08 18:36:24 -04:00
this._status = this._calculateStatus();
if (emitEvent) {
this._statusChanges.emit(this._status);
}
2016-06-08 18:36:24 -04:00
if (isPresent(this._parent)) {
this._parent._updateControlsErrors(emitEvent);
2016-06-08 18:36:24 -04:00
}
}
/** @internal */
_initObservables() {
this._valueChanges = new EventEmitter();
this._statusChanges = new EventEmitter();
}
private _calculateStatus(): string {
if (isPresent(this._errors)) return INVALID;
if (this._anyControlsHaveStatus(PENDING)) return PENDING;
if (this._anyControlsHaveStatus(INVALID)) return INVALID;
return VALID;
}
/** @internal */
abstract _updateValue(): void;
/** @internal */
abstract _forEachChild(cb: Function): void;
/** @internal */
abstract _anyControls(condition: Function): boolean;
/** @internal */
_anyControlsHaveStatus(status: string): boolean {
return this._anyControls((control: AbstractControl) => control.status == status);
}
/** @internal */
_anyControlsDirty(): boolean {
return this._anyControls((control: AbstractControl) => control.dirty);
}
/** @internal */
_anyControlsTouched(): boolean {
return this._anyControls((control: AbstractControl) => control.touched);
}
/** @internal */
_updatePristine({onlySelf}: {onlySelf?: boolean} = {}): void {
this._pristine = !this._anyControlsDirty();
if (isPresent(this._parent) && !onlySelf) {
this._parent._updatePristine({onlySelf: onlySelf});
}
}
/** @internal */
_updateTouched({onlySelf}: {onlySelf?: boolean} = {}): void {
this._touched = this._anyControlsTouched();
if (isPresent(this._parent) && !onlySelf) {
this._parent._updateTouched({onlySelf: onlySelf});
}
}
2016-06-08 18:36:24 -04:00
}
/**
* Defines a part of a form that cannot be divided into other controls. `FormControl`s have values
* and
2016-06-08 18:36:24 -04:00
* validation state, which is determined by an optional validation function.
*
* `FormControl` is one of the three fundamental building blocks used to define forms in Angular,
* along
* with {@link FormGroup} and {@link FormArray}.
2016-06-08 18:36:24 -04:00
*
* ## Usage
*
* By default, a `FormControl` is created for every `<input>` or other form component.
* With {@link FormControlDirective} or {@link FormGroupDirective} an existing {@link FormControl}
* can be bound to a DOM element instead. This `FormControl` can be configured with a custom
2016-06-08 18:36:24 -04:00
* validation function.
*
* @stable
2016-06-08 18:36:24 -04:00
*/
export class FormControl extends AbstractControl {
2016-06-08 18:36:24 -04:00
/** @internal */
_onChange: Function[] = [];
2016-06-08 18:36:24 -04:00
constructor(
value: any = null, validator: ValidatorFn|ValidatorFn[] = null,
asyncValidator: AsyncValidatorFn|AsyncValidatorFn[] = null) {
super(coerceToValidator(validator), coerceToAsyncValidator(asyncValidator));
2016-06-08 18:36:24 -04:00
this._value = value;
this.updateValueAndValidity({onlySelf: true, emitEvent: false});
this._initObservables();
}
/**
* Set the value of the form control to `value`.
2016-06-08 18:36:24 -04:00
*
* If `onlySelf` is `true`, this change will only affect the validation of this `FormControl`
2016-06-08 18:36:24 -04:00
* and not its parent component. If `emitEvent` is `true`, this change will cause a
* `valueChanges` event on the `FormControl` to be emitted. Both of these options default to
2016-06-08 18:36:24 -04:00
* `false`.
*
* If `emitModelToViewChange` is `true`, the view will be notified about the new value
* via an `onChange` event. This is the default behavior if `emitModelToViewChange` is not
* specified.
*
* If `emitViewToModelChange` is `true`, an ngModelChange event will be fired to update the
* model. This is the default behavior if `emitViewToModelChange` is not specified.
2016-06-08 18:36:24 -04:00
*/
setValue(value: any, {onlySelf, emitEvent, emitModelToViewChange, emitViewToModelChange}: {
2016-06-08 18:36:24 -04:00
onlySelf?: boolean,
emitEvent?: boolean,
emitModelToViewChange?: boolean,
emitViewToModelChange?: boolean
2016-06-08 18:36:24 -04:00
} = {}): void {
emitModelToViewChange = isPresent(emitModelToViewChange) ? emitModelToViewChange : true;
emitViewToModelChange = isPresent(emitViewToModelChange) ? emitViewToModelChange : true;
2016-06-08 18:36:24 -04:00
this._value = value;
if (this._onChange.length && emitModelToViewChange) {
this._onChange.forEach((changeFn) => changeFn(this._value, emitViewToModelChange));
}
2016-06-08 18:36:24 -04:00
this.updateValueAndValidity({onlySelf: onlySelf, emitEvent: emitEvent});
}
/**
* This function is functionally the same as updateValue() at this level. It exists for
* symmetry with patchValue() on FormGroups and FormArrays, where it does behave differently.
*/
patchValue(value: any, options: {
onlySelf?: boolean,
emitEvent?: boolean,
emitModelToViewChange?: boolean,
emitViewToModelChange?: boolean
} = {}): void {
this.setValue(value, options);
}
reset(value: any = null, {onlySelf}: {onlySelf?: boolean} = {}): void {
this.markAsPristine({onlySelf: onlySelf});
this.markAsUntouched({onlySelf: onlySelf});
this.setValue(value, {onlySelf: onlySelf});
}
2016-06-08 18:36:24 -04:00
/**
* @internal
*/
_updateValue() {}
/**
* @internal
*/
_anyControls(condition: Function): boolean { return false; }
2016-06-08 18:36:24 -04:00
/**
* Register a listener for change events.
*/
registerOnChange(fn: Function): void { this._onChange.push(fn); }
/**
* @internal
*/
_forEachChild(cb: Function): void {}
2016-06-08 18:36:24 -04:00
}
/**
* Defines a part of a form, of fixed length, that can contain other controls.
*
* A `FormGroup` aggregates the values of each {@link FormControl} in the group.
* The status of a `FormGroup` depends on the status of its children.
2016-06-08 18:36:24 -04:00
* If one of the controls in a group is invalid, the entire group is invalid.
* Similarly, if a control changes its value, the entire group changes as well.
*
* `FormGroup` is one of the three fundamental building blocks used to define forms in Angular,
* along with {@link FormControl} and {@link FormArray}. {@link FormArray} can also contain other
2016-06-08 18:36:24 -04:00
* controls, but is of variable length.
*
*
* @stable
2016-06-08 18:36:24 -04:00
*/
export class FormGroup extends AbstractControl {
2016-06-08 18:36:24 -04:00
private _optionals: {[key: string]: boolean};
constructor(
public controls: {[key: string]: AbstractControl},
/* @deprecated */ optionals: {[key: string]: boolean} = null, validator: ValidatorFn = null,
asyncValidator: AsyncValidatorFn = null) {
2016-06-08 18:36:24 -04:00
super(validator, asyncValidator);
this._optionals = isPresent(optionals) ? optionals : {};
this._initObservables();
this._setParentForControls();
this.updateValueAndValidity({onlySelf: true, emitEvent: false});
}
/**
* Register a control with the group's list of controls.
*/
registerControl(name: string, control: AbstractControl): AbstractControl {
if (this.controls[name]) return this.controls[name];
2016-06-08 18:36:24 -04:00
this.controls[name] = control;
control.setParent(this);
return control;
2016-06-08 18:36:24 -04:00
}
/**
* Add a control to this group.
*/
addControl(name: string, control: AbstractControl): void {
this.registerControl(name, control);
this.updateValueAndValidity();
}
/**
* Remove a control from this group.
*/
removeControl(name: string): void {
StringMapWrapper.delete(this.controls, name);
this.updateValueAndValidity();
}
/**
* Mark the named control as non-optional.
* @deprecated
2016-06-08 18:36:24 -04:00
*/
include(controlName: string): void {
StringMapWrapper.set(this._optionals, controlName, true);
this.updateValueAndValidity();
}
/**
* Mark the named control as optional.
* @deprecated
2016-06-08 18:36:24 -04:00
*/
exclude(controlName: string): void {
StringMapWrapper.set(this._optionals, controlName, false);
this.updateValueAndValidity();
}
/**
* Check whether there is a control with the given name in the group.
*/
contains(controlName: string): boolean {
var c = StringMapWrapper.contains(this.controls, controlName);
return c && this._included(controlName);
}
setValue(value: {[key: string]: any}, {onlySelf}: {onlySelf?: boolean} = {}): void {
this._checkAllValuesPresent(value);
StringMapWrapper.forEach(value, (newValue: any, name: string) => {
this._throwIfControlMissing(name);
this.controls[name].setValue(newValue, {onlySelf: true});
});
this.updateValueAndValidity({onlySelf: onlySelf});
}
patchValue(value: {[key: string]: any}, {onlySelf}: {onlySelf?: boolean} = {}): void {
StringMapWrapper.forEach(value, (newValue: any, name: string) => {
if (this.controls[name]) {
this.controls[name].patchValue(newValue, {onlySelf: true});
}
});
this.updateValueAndValidity({onlySelf: onlySelf});
}
reset(value: any = {}, {onlySelf}: {onlySelf?: boolean} = {}): void {
this._forEachChild((control: AbstractControl, name: string) => {
control.reset(value[name], {onlySelf: true});
});
this.updateValueAndValidity({onlySelf: onlySelf});
this._updatePristine({onlySelf: onlySelf});
this._updateTouched({onlySelf: onlySelf});
}
/** @internal */
_throwIfControlMissing(name: string): void {
if (!Object.keys(this.controls).length) {
throw new BaseException(`
There are no form controls registered with this group yet. If you're using ngModel,
you may want to check next tick (e.g. use setTimeout).
`);
}
if (!this.controls[name]) {
throw new BaseException(`Cannot find form control with name: ${name}.`);
}
}
/** @internal */
2016-07-15 19:26:19 -04:00
_forEachChild(cb: (v: any, k: string) => void): void {
StringMapWrapper.forEach(this.controls, cb);
}
2016-06-08 18:36:24 -04:00
/** @internal */
_setParentForControls() {
this._forEachChild((control: AbstractControl, name: string) => { control.setParent(this); });
2016-06-08 18:36:24 -04:00
}
/** @internal */
_updateValue() { this._value = this._reduceValue(); }
/** @internal */
_anyControls(condition: Function): boolean {
2016-06-08 18:36:24 -04:00
var res = false;
this._forEachChild((control: AbstractControl, name: string) => {
res = res || (this.contains(name) && condition(control));
2016-06-08 18:36:24 -04:00
});
return res;
}
/** @internal */
_reduceValue() {
return this._reduceChildren(
{}, (acc: {[k: string]: AbstractControl}, control: AbstractControl, name: string) => {
acc[name] = control.value;
return acc;
});
}
/** @internal */
_reduceChildren(initValue: any, fn: Function) {
var res = initValue;
this._forEachChild((control: AbstractControl, name: string) => {
2016-06-08 18:36:24 -04:00
if (this._included(name)) {
res = fn(res, control, name);
}
});
return res;
}
/** @internal */
_included(controlName: string): boolean {
var isOptional = StringMapWrapper.contains(this._optionals, controlName);
return !isOptional || StringMapWrapper.get(this._optionals, controlName);
}
/** @internal */
_checkAllValuesPresent(value: any): void {
this._forEachChild((control: AbstractControl, name: string) => {
if (value[name] === undefined) {
throw new BaseException(`Must supply a value for form control with name: '${name}'.`);
}
});
}
2016-06-08 18:36:24 -04:00
}
/**
* Defines a part of a form, of variable length, that can contain other controls.
*
* A `FormArray` aggregates the values of each {@link FormControl} in the group.
* The status of a `FormArray` depends on the status of its children.
2016-06-08 18:36:24 -04:00
* If one of the controls in a group is invalid, the entire array is invalid.
* Similarly, if a control changes its value, the entire array changes as well.
*
* `FormArray` is one of the three fundamental building blocks used to define forms in Angular,
* along with {@link FormControl} and {@link FormGroup}. {@link FormGroup} can also contain
2016-06-08 18:36:24 -04:00
* other controls, but is of fixed length.
*
* ## Adding or removing controls
*
* To change the controls in the array, use the `push`, `insert`, or `removeAt` methods
* in `FormArray` itself. These methods ensure the controls are properly tracked in the
2016-06-08 18:36:24 -04:00
* form's hierarchy. Do not modify the array of `AbstractControl`s used to instantiate
* the `FormArray` directly, as that will result in strange and unexpected behavior such
2016-06-08 18:36:24 -04:00
* as broken change detection.
*
*
* @stable
2016-06-08 18:36:24 -04:00
*/
export class FormArray extends AbstractControl {
constructor(
public controls: AbstractControl[], validator: ValidatorFn = null,
asyncValidator: AsyncValidatorFn = null) {
2016-06-08 18:36:24 -04:00
super(validator, asyncValidator);
this._initObservables();
this._setParentForControls();
this.updateValueAndValidity({onlySelf: true, emitEvent: false});
}
/**
* Get the {@link AbstractControl} at the given `index` in the array.
*/
at(index: number): AbstractControl { return this.controls[index]; }
/**
* Insert a new {@link AbstractControl} at the end of the array.
*/
push(control: AbstractControl): void {
this.controls.push(control);
control.setParent(this);
this.updateValueAndValidity();
}
/**
* Insert a new {@link AbstractControl} at the given `index` in the array.
*/
insert(index: number, control: AbstractControl): void {
ListWrapper.insert(this.controls, index, control);
control.setParent(this);
this.updateValueAndValidity();
}
/**
* Remove the control at the given `index` in the array.
*/
removeAt(index: number): void {
ListWrapper.removeAt(this.controls, index);
this.updateValueAndValidity();
}
/**
* Length of the control array.
*/
get length(): number { return this.controls.length; }
setValue(value: any[], {onlySelf}: {onlySelf?: boolean} = {}): void {
this._checkAllValuesPresent(value);
value.forEach((newValue: any, index: number) => {
this._throwIfControlMissing(index);
this.at(index).setValue(newValue, {onlySelf: true});
});
this.updateValueAndValidity({onlySelf: onlySelf});
}
patchValue(value: any[], {onlySelf}: {onlySelf?: boolean} = {}): void {
value.forEach((newValue: any, index: number) => {
if (this.at(index)) {
this.at(index).patchValue(newValue, {onlySelf: true});
}
});
this.updateValueAndValidity({onlySelf: onlySelf});
}
reset(value: any = [], {onlySelf}: {onlySelf?: boolean} = {}): void {
this._forEachChild((control: AbstractControl, index: number) => {
control.reset(value[index], {onlySelf: true});
});
this.updateValueAndValidity({onlySelf: onlySelf});
this._updatePristine({onlySelf: onlySelf});
this._updateTouched({onlySelf: onlySelf});
}
/** @internal */
_throwIfControlMissing(index: number): void {
if (!this.controls.length) {
throw new BaseException(`
There are no form controls registered with this array yet. If you're using ngModel,
you may want to check next tick (e.g. use setTimeout).
`);
}
if (!this.at(index)) {
throw new BaseException(`Cannot find form control at index ${index}`);
}
}
/** @internal */
_forEachChild(cb: Function): void {
this.controls.forEach((control: AbstractControl, index: number) => { cb(control, index); });
}
2016-06-08 18:36:24 -04:00
/** @internal */
_updateValue(): void { this._value = this.controls.map((control) => control.value); }
/** @internal */
_anyControls(condition: Function): boolean {
return this.controls.some((control: AbstractControl) => condition(control));
2016-06-08 18:36:24 -04:00
}
/** @internal */
_setParentForControls(): void {
this._forEachChild((control: AbstractControl) => { control.setParent(this); });
2016-06-08 18:36:24 -04:00
}
/** @internal */
_checkAllValuesPresent(value: any): void {
this._forEachChild((control: AbstractControl, i: number) => {
if (value[i] === undefined) {
throw new BaseException(`Must supply a value for form control at index: ${i}.`);
}
});
}
2016-06-08 18:36:24 -04:00
}