Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit dbe381f

Browse files
lrlopezpetebacondarwin
authored andcommitted
feat(ngModelOptions): custom triggers and debounce of ngModel updates
By default, any change to an input will trigger an immediate model update, form validation and run a $digest. This is not always desirable, especially when you have a large number of bindings to update. This PR implements a new directive `ngModelOptions`, which allow you to override this default behavior in several ways. It is implemented as an attribute, to which you pass an Angular expression, which evaluates to an **options** object. All inputs, using ngModel, will search for this directive in their ancestors and use it if found. This makes it easy to provide options for a whole form or even the whole page, as well as specifying exceptions for individual inputs. * You can specify what events trigger an update to the model by providing an `updateOn` property on the **options** object. This property takes a string containing a space separated list of events. For example, `ng-model-options="{ updateOn: 'blur' }"` will update the model only after the input loses focus. There is a special pseudo-event, called "default", which maps to the default event used by the input box normally. This is useful if you want to keep the default behavior and just add new events. * You can specify a debounce delay, how long to wait after the last triggering event before updating the model, by providing a `debounce` property on the **options** object. This property can be a simple number, the debounce delay for all events. For example, `ng-model-options="{ debounce: 500 }" will ensure the model is updated only when there has been a period 500ms since the last triggering event. The property can also be an object, where the keys map to events and the values are a corresponding debounce delay for that event. This can be useful to force immediate updates on some specific circumstances (like blur events). For example, `ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0} }"` This commit also brings to an end one of the longest running Pull Requests in the history of AngularJS (#2129)! A testament to the patience of @lrlopez. Closes #1285, #2129, #6945
1 parent e55c8bc commit dbe381f

File tree

4 files changed

+568
-63
lines changed

4 files changed

+568
-63
lines changed

docs/content/guide/forms.ngdoc

+76
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,82 @@ This allows us to extend the above example with these features:
181181

182182

183183

184+
# Custom triggers
185+
186+
By default, any change to the content will trigger a model update and form validation. You can
187+
override this behavior using the {@link ng.directive:ngModelOptions ngModelOptions} directive to
188+
bind only to specified list of events. I.e. `ng-model-options="{ updateOn: "blur" }"` will update
189+
and validate only after the control loses focus. You can set several events using a space delimited
190+
list. I.e. `ng-model-options="{ updateOn: 'mousedown blur' }"`
191+
192+
If you want to keep the default behavior and just add new events that may trigger the model update
193+
and validation, add "default" as one of the specified events.
194+
195+
I.e. `ng-model-options="{ updateOn: 'default blur' }"`
196+
197+
The following example shows how to override immediate updates. Changes on the inputs within the form will update the model
198+
only when the control loses focus (blur event).
199+
200+
<example>
201+
<file name="index.html">
202+
<div ng-controller="ControllerUpdateOn">
203+
<form>
204+
Name:
205+
<input type="text" ng-model="user.name" ng-model-options="{ updateOn: "blur" }" /><br />
206+
Other data:
207+
<input type="text" ng-model="user.data" /><br />
208+
</form>
209+
<pre>username = "{{user.name}}"</pre>
210+
</div>
211+
</file>
212+
<file name="script.js">
213+
function ControllerUpdateOn($scope) {
214+
$scope.user = {};
215+
}
216+
</file>
217+
</example>
218+
219+
220+
221+
# Non-immediate (debounced) model updates
222+
223+
You can delay the model update/validation by using the `debounce` key with the
224+
{@link ng.directive:ngModelOptions ngModelOptions} directive. This delay will also apply to
225+
parsers, validators and model flags like `$dirty` or `$pristine`.
226+
227+
I.e. `ng-model-options="{ debounce: 500 }"` will wait for half a second since
228+
the last content change before triggering the model update and form validation.
229+
230+
If custom triggers are used, custom debouncing timeouts can be set for each event using an object
231+
in `debounce`. This can be useful to force immediate updates on some specific circumstances
232+
(like blur events).
233+
234+
I.e. `ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0 } }"`
235+
236+
If those attributes are added to an element, they will be applied to all the child elements and controls that inherit from it unless they are
237+
overridden.
238+
239+
This example shows how to debounce model changes. Model will be updated only 250 milliseconds after last change.
240+
241+
<example>
242+
<file name="index.html">
243+
<div ng-controller="ControllerUpdateOn">
244+
<form>
245+
Name:
246+
<input type="text" ng-model="user.name" ng-model-options="{ debounce: 250 }" /><br />
247+
</form>
248+
<pre>username = "{{user.name}}"</pre>
249+
</div>
250+
</file>
251+
<file name="script.js">
252+
function ControllerUpdateOn($scope) {
253+
$scope.user = {};
254+
}
255+
</file>
256+
</example>
257+
258+
259+
184260
# Custom Validation
185261

186262
Angular provides basic implementation for most common html5 {@link ng.directive:input input}

src/AngularPublic.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
requiredDirective,
4747
requiredDirective,
4848
ngValueDirective,
49+
ngModelOptionsDirective,
4950
ngAttributeAliasDirectives,
5051
ngEventDirectives,
5152
@@ -183,7 +184,8 @@ function publishExternalAPI(angular){
183184
ngChange: ngChangeDirective,
184185
required: requiredDirective,
185186
ngRequired: requiredDirective,
186-
ngValue: ngValueDirective
187+
ngValue: ngValueDirective,
188+
ngModelOptions: ngModelOptionsDirective
187189
}).
188190
directive({
189191
ngInclude: ngIncludeFillContentDirective

0 commit comments

Comments
 (0)