angular2
Version:
Angular 2 - a web framework for modern web apps
489 lines • 20.4 kB
JavaScript
'use strict';var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var lang_1 = require('angular2/src/facade/lang');
var async_1 = require('angular2/src/facade/async');
var promise_1 = require('angular2/src/facade/promise');
var collection_1 = require('angular2/src/facade/collection');
/**
* Indicates that a Control is valid, i.e. that no errors exist in the input value.
*/
exports.VALID = "VALID";
/**
* Indicates that a Control is invalid, i.e. that an error exists in the input value.
*/
exports.INVALID = "INVALID";
/**
* Indicates that a Control is pending, i.e. that async validation is occuring and
* errors are not yet available for the input value.
*/
exports.PENDING = "PENDING";
function isControl(control) {
return control instanceof AbstractControl;
}
exports.isControl = isControl;
function _find(control, path) {
if (lang_1.isBlank(path))
return null;
if (!(path instanceof Array)) {
path = path.split("/");
}
if (path instanceof Array && collection_1.ListWrapper.isEmpty(path))
return null;
return path
.reduce(function (v, name) {
if (v instanceof ControlGroup) {
return lang_1.isPresent(v.controls[name]) ? v.controls[name] : null;
}
else if (v instanceof ControlArray) {
var index = name;
return lang_1.isPresent(v.at(index)) ? v.at(index) : null;
}
else {
return null;
}
}, control);
}
function toObservable(r) {
return promise_1.PromiseWrapper.isPromise(r) ? async_1.ObservableWrapper.fromPromise(r) : r;
}
/**
*
*/
var AbstractControl = (function () {
function AbstractControl(validator, asyncValidator) {
this.validator = validator;
this.asyncValidator = asyncValidator;
this._pristine = true;
this._touched = false;
}
Object.defineProperty(AbstractControl.prototype, "value", {
get: function () { return this._value; },
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractControl.prototype, "status", {
get: function () { return this._status; },
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractControl.prototype, "valid", {
get: function () { return this._status === exports.VALID; },
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractControl.prototype, "errors", {
/**
* Returns the errors of this control.
*/
get: function () { return this._errors; },
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractControl.prototype, "pristine", {
get: function () { return this._pristine; },
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractControl.prototype, "dirty", {
get: function () { return !this.pristine; },
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractControl.prototype, "touched", {
get: function () { return this._touched; },
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractControl.prototype, "untouched", {
get: function () { return !this._touched; },
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractControl.prototype, "valueChanges", {
get: function () { return this._valueChanges; },
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractControl.prototype, "statusChanges", {
get: function () { return this._statusChanges; },
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractControl.prototype, "pending", {
get: function () { return this._status == exports.PENDING; },
enumerable: true,
configurable: true
});
AbstractControl.prototype.markAsTouched = function () { this._touched = true; };
AbstractControl.prototype.markAsDirty = function (_a) {
var onlySelf = (_a === void 0 ? {} : _a).onlySelf;
onlySelf = lang_1.normalizeBool(onlySelf);
this._pristine = false;
if (lang_1.isPresent(this._parent) && !onlySelf) {
this._parent.markAsDirty({ onlySelf: onlySelf });
}
};
AbstractControl.prototype.markAsPending = function (_a) {
var onlySelf = (_a === void 0 ? {} : _a).onlySelf;
onlySelf = lang_1.normalizeBool(onlySelf);
this._status = exports.PENDING;
if (lang_1.isPresent(this._parent) && !onlySelf) {
this._parent.markAsPending({ onlySelf: onlySelf });
}
};
AbstractControl.prototype.setParent = function (parent) { this._parent = parent; };
AbstractControl.prototype.updateValueAndValidity = function (_a) {
var _b = _a === void 0 ? {} : _a, onlySelf = _b.onlySelf, emitEvent = _b.emitEvent;
onlySelf = lang_1.normalizeBool(onlySelf);
emitEvent = lang_1.isPresent(emitEvent) ? emitEvent : true;
this._updateValue();
this._errors = this._runValidator();
this._status = this._calculateStatus();
if (this._status == exports.VALID || this._status == exports.PENDING) {
this._runAsyncValidator(emitEvent);
}
if (emitEvent) {
async_1.ObservableWrapper.callNext(this._valueChanges, this._value);
async_1.ObservableWrapper.callNext(this._statusChanges, this._status);
}
if (lang_1.isPresent(this._parent) && !onlySelf) {
this._parent.updateValueAndValidity({ onlySelf: onlySelf, emitEvent: emitEvent });
}
};
AbstractControl.prototype._runValidator = function () { return lang_1.isPresent(this.validator) ? this.validator(this) : null; };
AbstractControl.prototype._runAsyncValidator = function (emitEvent) {
var _this = this;
if (lang_1.isPresent(this.asyncValidator)) {
this._status = exports.PENDING;
this._cancelExistingSubscription();
var obs = toObservable(this.asyncValidator(this));
this._asyncValidationSubscription =
async_1.ObservableWrapper.subscribe(obs, function (res) { return _this.setErrors(res, { emitEvent: emitEvent }); });
}
};
AbstractControl.prototype._cancelExistingSubscription = function () {
if (lang_1.isPresent(this._asyncValidationSubscription)) {
async_1.ObservableWrapper.dispose(this._asyncValidationSubscription);
}
};
/**
* Sets errors on a control.
*
* 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 Control("someLogin");
* login.setErrors({
* "notUnique": true
* });
*
* expect(login.valid).toEqual(false);
* expect(login.errors).toEqual({"notUnique": true});
*
* login.updateValue("someOtherLogin");
*
* expect(login.valid).toEqual(true);
* ```
*/
AbstractControl.prototype.setErrors = function (errors, _a) {
var emitEvent = (_a === void 0 ? {} : _a).emitEvent;
emitEvent = lang_1.isPresent(emitEvent) ? emitEvent : true;
this._errors = errors;
this._status = this._calculateStatus();
if (emitEvent) {
async_1.ObservableWrapper.callNext(this._statusChanges, this._status);
}
if (lang_1.isPresent(this._parent)) {
this._parent._updateControlsErrors();
}
};
AbstractControl.prototype.find = function (path) { return _find(this, path); };
AbstractControl.prototype.getError = function (errorCode, path) {
if (path === void 0) { path = null; }
var control = lang_1.isPresent(path) && !collection_1.ListWrapper.isEmpty(path) ? this.find(path) : this;
if (lang_1.isPresent(control) && lang_1.isPresent(control._errors)) {
return collection_1.StringMapWrapper.get(control._errors, errorCode);
}
else {
return null;
}
};
AbstractControl.prototype.hasError = function (errorCode, path) {
if (path === void 0) { path = null; }
return lang_1.isPresent(this.getError(errorCode, path));
};
/** @internal */
AbstractControl.prototype._updateControlsErrors = function () {
this._status = this._calculateStatus();
if (lang_1.isPresent(this._parent)) {
this._parent._updateControlsErrors();
}
};
/** @internal */
AbstractControl.prototype._initObservables = function () {
this._valueChanges = new async_1.EventEmitter();
this._statusChanges = new async_1.EventEmitter();
};
AbstractControl.prototype._calculateStatus = function () {
if (lang_1.isPresent(this._errors))
return exports.INVALID;
if (this._anyControlsHaveStatus(exports.PENDING))
return exports.PENDING;
if (this._anyControlsHaveStatus(exports.INVALID))
return exports.INVALID;
return exports.VALID;
};
return AbstractControl;
})();
exports.AbstractControl = AbstractControl;
/**
* Defines a part of a form that cannot be divided into other controls. `Control`s have values and
* validation state, which is determined by an optional validation function.
*
* `Control` is one of the three fundamental building blocks used to define forms in Angular, along
* with {@link ControlGroup} and {@link ControlArray}.
*
* ##Usage
*
* By default, a `Control` is created for every `<input>` or other form component.
* With {@link NgFormControl} or {@link NgFormModel} an existing {@link Control} can be
* bound to a DOM element instead. This `Control` can be configured with a custom
* validation function.
*
* ### Example ([live demo](http://plnkr.co/edit/23DESOpbNnBpBHZt1BR4?p=preview))
*/
var Control = (function (_super) {
__extends(Control, _super);
function Control(value, validator, asyncValidator) {
if (value === void 0) { value = null; }
if (validator === void 0) { validator = null; }
if (asyncValidator === void 0) { asyncValidator = null; }
_super.call(this, validator, asyncValidator);
this._value = value;
this.updateValueAndValidity({ onlySelf: true, emitEvent: false });
this._initObservables();
}
/**
* Set the value of the control to `value`.
*
* If `onlySelf` is `true`, this change will only affect the validation of this `Control`
* and not its parent component. If `emitEvent` is `true`, this change will cause a
* `valueChanges` event on the `Control` to be emitted. Both of these options default to
* `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.
*/
Control.prototype.updateValue = function (value, _a) {
var _b = _a === void 0 ? {} : _a, onlySelf = _b.onlySelf, emitEvent = _b.emitEvent, emitModelToViewChange = _b.emitModelToViewChange;
emitModelToViewChange = lang_1.isPresent(emitModelToViewChange) ? emitModelToViewChange : true;
this._value = value;
if (lang_1.isPresent(this._onChange) && emitModelToViewChange)
this._onChange(this._value);
this.updateValueAndValidity({ onlySelf: onlySelf, emitEvent: emitEvent });
};
/**
* @internal
*/
Control.prototype._updateValue = function () { };
/**
* @internal
*/
Control.prototype._anyControlsHaveStatus = function (status) { return false; };
/**
* Register a listener for change events.
*/
Control.prototype.registerOnChange = function (fn) { this._onChange = fn; };
return Control;
})(AbstractControl);
exports.Control = Control;
/**
* Defines a part of a form, of fixed length, that can contain other controls.
*
* A `ControlGroup` aggregates the values and errors of each {@link Control} in the group. Thus, 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.
*
* `ControlGroup` is one of the three fundamental building blocks used to define forms in Angular,
* along with {@link Control} and {@link ControlArray}. {@link ControlArray} can also contain other
* controls, but is of variable length.
*
* ### Example ([live demo](http://plnkr.co/edit/23DESOpbNnBpBHZt1BR4?p=preview))
*/
var ControlGroup = (function (_super) {
__extends(ControlGroup, _super);
function ControlGroup(controls, optionals, validator, asyncValidator) {
if (optionals === void 0) { optionals = null; }
if (validator === void 0) { validator = null; }
if (asyncValidator === void 0) { asyncValidator = null; }
_super.call(this, validator, asyncValidator);
this.controls = controls;
this._optionals = lang_1.isPresent(optionals) ? optionals : {};
this._initObservables();
this._setParentForControls();
this.updateValueAndValidity({ onlySelf: true, emitEvent: false });
}
/**
* Add a control to this group.
*/
ControlGroup.prototype.addControl = function (name, control) {
this.controls[name] = control;
control.setParent(this);
};
/**
* Remove a control from this group.
*/
ControlGroup.prototype.removeControl = function (name) { collection_1.StringMapWrapper.delete(this.controls, name); };
/**
* Mark the named control as non-optional.
*/
ControlGroup.prototype.include = function (controlName) {
collection_1.StringMapWrapper.set(this._optionals, controlName, true);
this.updateValueAndValidity();
};
/**
* Mark the named control as optional.
*/
ControlGroup.prototype.exclude = function (controlName) {
collection_1.StringMapWrapper.set(this._optionals, controlName, false);
this.updateValueAndValidity();
};
/**
* Check whether there is a control with the given name in the group.
*/
ControlGroup.prototype.contains = function (controlName) {
var c = collection_1.StringMapWrapper.contains(this.controls, controlName);
return c && this._included(controlName);
};
/** @internal */
ControlGroup.prototype._setParentForControls = function () {
var _this = this;
collection_1.StringMapWrapper.forEach(this.controls, function (control, name) { control.setParent(_this); });
};
/** @internal */
ControlGroup.prototype._updateValue = function () { this._value = this._reduceValue(); };
/** @internal */
ControlGroup.prototype._anyControlsHaveStatus = function (status) {
var _this = this;
var res = false;
collection_1.StringMapWrapper.forEach(this.controls, function (control, name) {
res = res || (_this.contains(name) && control.status == status);
});
return res;
};
/** @internal */
ControlGroup.prototype._reduceValue = function () {
return this._reduceChildren({}, function (acc, control, name) {
acc[name] = control.value;
return acc;
});
};
/** @internal */
ControlGroup.prototype._reduceChildren = function (initValue, fn) {
var _this = this;
var res = initValue;
collection_1.StringMapWrapper.forEach(this.controls, function (control, name) {
if (_this._included(name)) {
res = fn(res, control, name);
}
});
return res;
};
/** @internal */
ControlGroup.prototype._included = function (controlName) {
var isOptional = collection_1.StringMapWrapper.contains(this._optionals, controlName);
return !isOptional || collection_1.StringMapWrapper.get(this._optionals, controlName);
};
return ControlGroup;
})(AbstractControl);
exports.ControlGroup = ControlGroup;
/**
* Defines a part of a form, of variable length, that can contain other controls.
*
* A `ControlArray` aggregates the values and errors of each {@link Control} in the group. Thus, 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.
*
* `ControlArray` is one of the three fundamental building blocks used to define forms in Angular,
* along with {@link Control} and {@link ControlGroup}. {@link ControlGroup} can also contain
* 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 `ControlArray` itself. These methods ensure the controls are properly tracked in the
* form's hierarchy. Do not modify the array of `AbstractControl`s used to instantiate
* the `ControlArray` directly, as that will result in strange and unexpected behavior such
* as broken change detection.
*
* ### Example ([live demo](http://plnkr.co/edit/23DESOpbNnBpBHZt1BR4?p=preview))
*/
var ControlArray = (function (_super) {
__extends(ControlArray, _super);
function ControlArray(controls, validator, asyncValidator) {
if (validator === void 0) { validator = null; }
if (asyncValidator === void 0) { asyncValidator = null; }
_super.call(this, validator, asyncValidator);
this.controls = controls;
this._initObservables();
this._setParentForControls();
this.updateValueAndValidity({ onlySelf: true, emitEvent: false });
}
/**
* Get the {@link AbstractControl} at the given `index` in the array.
*/
ControlArray.prototype.at = function (index) { return this.controls[index]; };
/**
* Insert a new {@link AbstractControl} at the end of the array.
*/
ControlArray.prototype.push = function (control) {
this.controls.push(control);
control.setParent(this);
this.updateValueAndValidity();
};
/**
* Insert a new {@link AbstractControl} at the given `index` in the array.
*/
ControlArray.prototype.insert = function (index, control) {
collection_1.ListWrapper.insert(this.controls, index, control);
control.setParent(this);
this.updateValueAndValidity();
};
/**
* Remove the control at the given `index` in the array.
*/
ControlArray.prototype.removeAt = function (index) {
collection_1.ListWrapper.removeAt(this.controls, index);
this.updateValueAndValidity();
};
Object.defineProperty(ControlArray.prototype, "length", {
/**
* Length of the control array.
*/
get: function () { return this.controls.length; },
enumerable: true,
configurable: true
});
/** @internal */
ControlArray.prototype._updateValue = function () { this._value = this.controls.map(function (control) { return control.value; }); };
/** @internal */
ControlArray.prototype._anyControlsHaveStatus = function (status) {
return this.controls.some(function (c) { return c.status == status; });
};
/** @internal */
ControlArray.prototype._setParentForControls = function () {
var _this = this;
this.controls.forEach(function (control) { control.setParent(_this); });
};
return ControlArray;
})(AbstractControl);
exports.ControlArray = ControlArray;
//# sourceMappingURL=model.js.map