This directive allows you to modify the behaviour of ngModel
directives within your
application. You can specify an ngModelOptions
directive on any element. All ngModel
directives will use the options of their nearest ngModelOptions
ancestor.
The ngModelOptions
settings are found by evaluating the value of the attribute directive as
an AngularJS expression. This expression should evaluate to an object, whose properties contain
the settings. For example: <div ng-model-options="{ debounce: 100 }"
.
You can specify that an ngModelOptions
setting should be inherited from a parent ngModelOptions
directive by giving it the value of "$inherit"
.
Then it will inherit that setting from the first ngModelOptions
directive found by traversing up the
DOM tree. If there is no ancestor element containing an ngModelOptions
directive then default settings
will be used.
For example given the following fragment of HTML
<div ng-model-options="{ allowInvalid: true, debounce: 200 }">
<form ng-model-options="{ updateOn: 'blur', allowInvalid: '$inherit' }">
<input ng-model-options="{ updateOn: 'default', allowInvalid: '$inherit' }" />
</form>
</div>
the input
element will have the following settings
{ allowInvalid: true, updateOn: 'default', debounce: 0 }
Notice that the debounce
setting was not inherited and used the default value instead.
You can specify that all undefined settings are automatically inherited from an ancestor by
including a property with key of "*"
and value of "$inherit"
.
For example given the following fragment of HTML
<div ng-model-options="{ allowInvalid: true, debounce: 200 }">
<form ng-model-options="{ updateOn: 'blur', "*": '$inherit' }">
<input ng-model-options="{ updateOn: 'default', "*": '$inherit' }" />
</form>
</div>
the input
element will have the following settings
{ allowInvalid: true, updateOn: 'default', debounce: 200 }
Notice that the debounce
setting now inherits the value from the outer <div>
element.
If you are creating a reusable component then you should be careful when using "*": "$inherit"
since you may inadvertently inherit a setting in the future that changes the behavior of your component.
The updateOn
and debounce
properties allow you to specify a custom list of events that will
trigger a model update and/or a debouncing delay so that the actual update only takes place when
a timer expires; this timer will be reset after another change takes place.
Given the nature of ngModelOptions
, the value displayed inside input fields in the view might
be different from the value in the actual model. This means that if you update the model you
should also invoke ngModel.NgModelController
on the relevant input field in
order to make sure it is synchronized with the model and that any debounced action is canceled.
The easiest way to reference the control's ngModel.NgModelController
method is by making sure the input is placed inside a form that has a name
attribute. This is
important because form
controllers are published to the related scope under the name in their
name
attribute.
Any pending changes will take place immediately when an enclosing form is submitted via the
submit
event. Note that ngClick
events will occur before the model is updated. Use ngSubmit
to have access to the updated model.
The following example shows how to override immediate updates. Changes on the inputs within the
form will update the model only when the control loses focus (blur event). If escape
key is
pressed while the input field is focused, the value is reset to the value in the current model.
<div ng-controller="ExampleController">
<form name="userForm">
<label>
Name:
<input type="text" name="userName"
ng-model="user.name"
ng-model-options="{ updateOn: 'blur' }"
ng-keyup="cancel($event)" />
</label><br />
<label>
Other data:
<input type="text" ng-model="user.data" />
</label><br />
</form>
<pre>user.name = <span ng-bind="user.name"></span></pre>
</div>
angular.module('optionsExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.user = { name: 'say', data: '' };
$scope.cancel = function(e) {
if (e.keyCode === 27) {
$scope.userForm.userName.$rollbackViewValue();
}
};
}]);
var model = element(by.binding('user.name'));
var input = element(by.model('user.name'));
var other = element(by.model('user.data'));
it('should allow custom events', function() {
input.sendKeys(' hello');
input.click();
expect(model.getText()).toEqual('say');
other.click();
expect(model.getText()).toEqual('say hello');
});
it('should $rollbackViewValue when model changes', function() {
input.sendKeys(' hello');
expect(input.getAttribute('value')).toEqual('say hello');
input.sendKeys(protractor.Key.ESCAPE);
expect(input.getAttribute('value')).toEqual('say');
other.click();
expect(model.getText()).toEqual('say');
});
The next example shows how to debounce model changes. Model will be updated only 1 sec after last change.
If the Clear
button is pressed, any debounced action is canceled and the value becomes empty.
<div ng-controller="ExampleController">
<form name="userForm">
Name:
<input type="text" name="userName"
ng-model="user.name"
ng-model-options="{ debounce: 1000 }" />
<button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button><br />
</form>
<pre>user.name = <span ng-bind="user.name"></span></pre>
</div>
angular.module('optionsExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.user = { name: 'say' };
}]);
This example shows the relationship between "default" update events and
additional updateOn
triggers.
default
events are those that are bound to the control, and when fired, update the $viewValue
via $setViewValue. Every event that is not listed
in updateOn
is considered a "default" event, since different control types have different
default events.
The control in this example updates by "default", "click", and "blur", with different debounce
values. You can see that "click" doesn't have an individual debounce
value -
therefore it uses the *
debounce value.
There is also a button that calls $setViewValue
directly with a "custom" event. Since "custom" is not defined in the updateOn
list,
it is considered a "default" event and will update the
control if "default" is defined in updateOn
, and will receive the "default" debounce value.
Note that this is just to illustrate how custom controls would possibly call $setViewValue
.
You can change the updateOn
and debounce
configuration to test different scenarios. This
is done with $overrideModelOptions.
<model-update-demo></model-update-demo>
angular.module('optionsExample', [])
.component('modelUpdateDemo', {
templateUrl: 'template.html',
controller: function() {
this.name = 'Chinua';
this.options = {
updateOn: 'default blur click',
debounce: {
default: 2000,
blur: 0,
'*': 1000
}
};
this.updateEvents = function() {
var eventList = this.options.updateOn.split(' ');
eventList.push('*');
var events = {};
for (var i = 0; i < eventList.length; i++) {
events[eventList[i]] = this.options.debounce[eventList[i]];
}
this.events = events;
};
this.updateOptions = function() {
var options = angular.extend(this.options, {
updateOn: Object.keys(this.events).join(' ').replace('*', ''),
debounce: this.events
});
this.form.input.$overrideModelOptions(options);
};
// Initialize the event form
this.updateEvents();
}
});
<form name="$ctrl.form">
Input: <input type="text" name="input" ng-model="$ctrl.name" ng-model-options="$ctrl.options" />
</form>
Model: <tt>{{$ctrl.name}}</tt>
<hr>
<button ng-click="$ctrl.form.input.$setViewValue('some value', 'custom')">Trigger setViewValue with 'some value' and 'custom' event</button>
<hr>
<form ng-submit="$ctrl.updateOptions()">
<b>updateOn</b><br>
<input type="text" ng-model="$ctrl.options.updateOn" ng-change="$ctrl.updateEvents()" ng-model-options="{debounce: 500}">
<table>
<tr>
<th>Option</th>
<th>Debounce value</th>
</tr>
<tr ng-repeat="(key, value) in $ctrl.events">
<td>{{key}}</td>
<td><input type="number" ng-model="$ctrl.events[key]" /></td>
</tr>
</table>
<br>
<input type="submit" value="Update options">
</form>
The default behaviour in ngModel
is that the model value is set to undefined
when the
validation determines that the value is invalid. By setting the allowInvalid
property to true,
the model will still be updated even if the value is invalid.
By setting the getterSetter
property to true you are telling ngModel that the ngModel
expression
on the scope refers to a "getter/setter" function rather than the value itself.
The following example shows how to bind to getter/setters:
<div ng-controller="ExampleController">
<form name="userForm">
<label>
Name:
<input type="text" name="userName"
ng-model="user.name"
ng-model-options="{ getterSetter: true }" />
</label>
</form>
<pre>user.name = <span ng-bind="user.name()"></span></pre>
</div>
angular.module('getterSetterExample', [])
.controller('ExampleController', ['$scope', function($scope) {
var _name = 'Brian';
$scope.user = {
name: function(newName) {
return angular.isDefined(newName) ? (_name = newName) : _name;
}
};
}]);
You can specify the timezone that date/time input directives expect by providing its name in the
timezone
property.
The ngModelOptions
expression is only evaluated once when the directive is linked; it is not
watched for changes. However, it is possible to override the options on a single
ngModel.NgModelController
instance with
NgModelController#$overrideModelOptions()
.
See also the example for
Default events, extra triggers, and catch-all debounce values.
<ANY
ng-model-options="Object">
...
</ANY>
Param | Type | Details |
---|---|---|
ngModelOptions | Object |
options to apply to
|