-
Notifications
You must be signed in to change notification settings - Fork 27.5k
feat(ngModelOptions): Model update behavior can now be customized #6945
Conversation
Thanks for the PR! Please check the items below to help us merge this faster. See the contributing docs for more information.
If you need to make changes to your pull request, you can update the commit with Thanks again for your help! |
What about setting $dirty etc. when there's a viewValue, but the model hasn't been set? Is this supported or is everything delayed? |
@@ -181,6 +181,69 @@ This allows us to extend the above example with these features: | |||
|
|||
|
|||
|
|||
# Non-immediate (debounced) or custom triggered model updates |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have a simpler title here? Perhaps even split out the two different features ("custom triggers" and "debounced updates") into two sections?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
@Narretz, everything is delayed until the model is set. |
If you want to keep the default behavior and just add new events that may trigger the model update | ||
and validation, add "default" as one of the specified events. I.e. `ng-model-options="{ updateOn: ["default", "blur"] }"` | ||
|
||
You can delay the model update/validation by writing a `debounce` key. I.e. `ng-model-options="{ debounce: 500 }"` will wait for half a second since |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably make it clear that no update of any kind occurs till the debounce resolved. I.E. No parsers, nor validators are run and $pristine is not affected.
By default, any change on the content will trigger an immediate model update and form validation. This PR implements a new directive `ng-model-options` that allow you to override this default behavior in several ways. You should specify an object with the different parameters. For example, it allows to trigger an update only when a particular event or list of events is received by the input using the `updateOn` key. Should you need multiple events, just assign an array to it. I.e. `ng-model-options="{ updateOn: 'blur' }"` will update and validate only after the control loses focus. If you want to keep the default behavior and just add new events that may trigger the model update and validation, add "default" as one of the specified events. I.e. `ng-model-options="{ updateOn: ['default','submit'] }"` Also, with the `debounce` option, `ng-model-options` will allow deferring the actual model update until a timer expires. The timer will be reset each time an event is triggered. I.e. `ng-model-options="{ debounce: 500 }" for 500ms after the latest event. Custom timeouts for each event can be set for each event if you use an object in `debounce`. This can be useful to force immediate updates on some specific circumstances (like blur events). I.e. `ng-model-options="{ updateOn: ['default', 'blur'], debounce: { default: 500, blur: 0} }"` You can use the directive in any tag so its contents became the default settings for any child control, although they can be overridden. Closes angular#1285, angular#2129
Thanks for the suggestions @caitp and @IgorMinar. They make the PR simpler. I've amended the commit. |
* when a timer expires; this timer will be reset after another change takes place. | ||
* | ||
* @param {Object=} Object that contains options to apply to the current model. Valid keys are: | ||
* - updateOn: string specifying which event should be the input bound to. If an array is supplied instead, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have to support list of events as an array? if we said that only space delimited strings are allowed ('blur click'
) then we wouldn't need forEach
when registering listeners jquery/jqlite on
support space delimited list of events and we could generally simplify quite a bit of code. (var events = options.$updateOn || options.$updateOnDefault; element.on(events, function() { ... });
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or even
element.on(options.$updateOn || options.$updateOnDefault, function() { ... });
ok, I know that I left a lot of comments. @lrlopez, I don't mean to discourage you. This is a really good change, it just needs a bit more polish and then we can ship it. Good work! (also @petebacondarwin and @auser) |
Great feature 👍 |
|
||
element.on('keydown', function(event) { | ||
var key = event.keyCode; | ||
var deferListener = function(ev) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method takes the ev
param but is not passed a param when called further down...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! Corrected L958
Ok. This PR seems to be ready and got the green light from the AngularJS team. There is no hurry as we missed the beta5 deadline, so let's get this right. If anyone finds something wrong or has any proposal, I'll be glad to hear it. At the end of the road, I'd like to publicly thank to @petebacondarwin for investing so much time in this PR. His help has been invaluable from the beginning, so kudos to him! |
LGTM! @petebacondarwin unless you know of some unresolved issues let's get this in. thanks guys! |
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
@lrlopez @petebacondarwin Sadly there are still issues with programmatic updates of the model:
What do you think? |
Good spots @shahata . Can we start two new issues to deal with these? |
By default, any change on the content will trigger an immediate model update and form validation. This PR implements a new directive
ng-model-options
that allow you to override this default behavior in several ways.You should specify an object with the different parameters.
For example, it allows to trigger an update only when a particular event or list of events is received by the input using the
updateOn
key. Should you need multiple events, just use a space delimited string.I.e.
ng-model-options="{ updateOn: 'blur' }"
will update and validate only after the control loses focus.If you want to keep the default behavior and just add new events that may trigger the model update and validation, add "default" as one of the specified events.
I.e.
ng-model-options="{ updateOn: 'default submit' }"
Also, with the
debounce
option,ng-model-options
will allow deferring the actual model update until a timer expires. The timer will be reset each time an event is triggered.I.e. `ng-model-options="{ debounce: 500 }" for 500ms after the latest event.
Custom timeouts for each event can be set for each event if you use an object in
debounce
. This can be useful to force immediate updates on some specific circumstances (like blur events).I.e.
ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0} }"
You can use the directive in any tag so its contents became the default settings for any child control, although they can be overridden.
Closes #1285, #2129