Calling `$commitViewValue` was was dirtying the input, even if no update to the view
value was made.
For example, `updateOn` triggers and form submit may call `$commitViewValue` even
if the the view value had not changed.
Closes#7457Closes#7495
Move responsibility for pending and debouncing model updates into `NgModelController`.
Now input directives are only responsible for capturing changes to the input element's
value and then calling `$setViewValue` with the new value.
Calls to `$setViewValue(value)` change the `$viewValue` property but these changes are
not committed to the `$modelValue` until an `updateOn` trigger occurs (and any related
`debounce` has resolved).
The `$$lastCommittedViewValue` is now stored when `$setViewValue(value)` updates
the `$viewValue`, which allows the view to be "reset" by calling `$rollbackViewValue()`.
The new `$commitViewValue()` method allows developers to force the `$viewValue` to be
committed through to the `$modelValue` immediately, ignoring `updateOn` triggers and
`debounce` delays.
BREAKING CHANGE:
This commit changes the API on `NgModelController`, both semantically and
in terms of adding and renaming methods.
* `$setViewValue(value)` -
This method still changes the `$viewValue` but does not immediately commit this
change through to the `$modelValue` as it did previously.
Now the value is committed only when a trigger specified in an associated
`ngModelOptions` directive occurs. If `ngModelOptions` also has a `debounce` delay
specified for the trigger then the change will also be debounced before being
committed.
In most cases this should not have a significant impact on how `NgModelController`
is used: If `updateOn` includes `default` then `$setViewValue` will trigger
a (potentially debounced) commit immediately.
* `$cancelUpdate()` - is renamed to `$rollbackViewValue()` and has the same meaning,
which is to revert the current `$viewValue` back to the `$lastCommittedViewValue`,
to cancel any pending debounced updates and to re-render the input.
To migrate code that used `$cancelUpdate()` follow the example below:
Before:
```
$scope.resetWithCancel = function (e) {
if (e.keyCode == 27) {
$scope.myForm.myInput1.$cancelUpdate();
$scope.myValue = '';
}
};
```
After:
```
$scope.resetWithCancel = function (e) {
if (e.keyCode == 27) {
$scope.myForm.myInput1.$rollbackViewValue();
$scope.myValue = '';
}
}
```
It is reasonable to expect a digest to occur between an input element
compiling and the first user interaction. Rather than add digests to
each test this change moves it into the `compileInput` helper function.
Because of how the logic was set up, a value of `0` was assumed to be the
same as `undefined`, which meant that you couldn't override the default
debounce delay with a value of zero.
For example, the following assigned a debounce delay of 500ms to the `blur`
event.
```
ngModelOptions="{ updateOn: 'default blur', debounce: {'default': 500, 'blur':
0} }"
```
Closes#7205
Input controls require `ngModel` which in turn brings in the `ngModelOptions`
but since ngModel does this initialization in the post link function, the
order in which the directives are run is relevant.
Directives are sorted by priority and name but `ngModel`, `input` and `textarea`
have the same priority. It just happens that `textarea` is alphabetically
sorted and so linked before `ngModel` (unlike `input`).
This is a problem since inputs expect `ngModelController.$options`
to exist at post-link time and for `textarea` this has not happened.
This is solved easily by moving the initialization of `ngModel` to the
pre-link function.
Closes#7281Closes#7292
Certain versions of IE inexplicably trigger an input event in response to a placeholder
being set.
It is not possible to sniff for this behaviour nicely as the event is not triggered if
the element is not attached to the document, and the event triggers asynchronously so
it is not possible to accomplish this without deferring DOM compilation and slowing down
load times.
Closes#2614Closes#5960
The `$cancelUpdate()` method on `NgModelController` cancels any pending debounce
action and resets the view value by invoking `$render()`.
This method should be invoked before programmatic update to the model of inputs
that might have pending updates due to `ng-model-options` specifying `updateOn`
or `debounce` properties.
Fixes#6994Closes#7014
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
On older browser that don't support the new HTML5 inputs
and display a text input instead, the user is required to enter
the data in the corresponding ISO format. The value in `ng-model`
will always be a date.
E2e tests contain a workaround to a bug in webdriver,
see https://github.com/angular/protractor/issues/562.
Also adds weeks as format to the `dateFilter`.
Related to #757.
Closes#5864.
Add css animations when form or field status change to/from dirty,
pristine, valid or invalid. This works like animation system present
with ngClass, ngShow, etc.
Closes#5378
Because of a4e6d962, model is not updated on input/change between the
compositionstart and compositionend events. Unfortunately, the compositionend
event does not always happen prior to an input/change event.
This changeset calls the listener function to update the model after a
compositionend event is received.
Closes#6058Closes#5433
This change uses the regexp from Chromium/Blink to validate emails, and corrects
an error in the validation engine, which previously considered an invalid email
to be valid. Additionally, the regexp was invalidating emails with capital
letters, however this is not the behaviour recomended in the spec, or implemented
in Chromium.
Closes#5899Closes#5924
If an event was performed natively, jQuery sets the isTrigger property.
When triggering event manually, the field is not present. Manually
triggered events are performed synchronously which causes the "$digest
already in progress" error.
Closes#5293
Due to an earlier change, ngModelWatch() no longer returns a value to the
caller. This means the digest loop has no way to tell if the watch actually
modified anything and so can not schedule another pass.
This means any watches that watch form or model controller changes
(e.g. watches on form.$valid) that are scheduled prior to an ngModelWatch()
will not be able to see any changes made therin.
This commit fixes this behavior by returning the latest evaluated ng-model
value.
Closes#5258Closes#5282
Although modern browser support the "input" event, they still only fire
the "change" event when they auto complete form elements
other than the currently selected one.
Related to #1460
Due to animations, DOM might get destroyed much later than scope and so the element $destroy event
might get fired outside of $digest, which causes changes to the validation model go unobserved
until the next digest. By deregistering on scope event, the deregistration always happens
in $digest and the form validation model changes will be observed.
Closes#4226Closes#4779
`checkboxInputType` and `ngList` directives need to have special logic for whether
they are empty or not. Previously this had been hard coded into their
own directives or the `ngRequired` directive. This made it difficult to handle
these special cases.
This change factors out the question of whether an input is empty into a method
`$isEmpty` on the `ngModelController`. The `ngRequired` directive now uses this
method when testing for validity and directives, such as `checkbox` or `ngList`
can override it to apply logic specific to their needs.
Closes#3490, #3658, #2594
The input field email regex does't not match long domain extensions. This commit extends the email regexp to take a 6 character TLD.
Example 6-character TLDs include .museum and .travel - (e.g. allabout.travel).
In IE the model is not updated when the input value is modified using the context
menu, e.g. pasting from the clipboard, or cutting all or part of the current value.
To capture these changes, we bind to the proprietary 'paste' and 'cut' events.
Closes#1462
Changed the isolate scope binding options to:
- @attr - attribute binding (including interpolation)
- =model - by-directional model binding
- &expr - expression execution binding
This change simplifies the terminology as well as
number of choices available to the developer. It
also supports local name aliasing from the parent.
BREAKING CHANGE: isolate scope bindings definition has changed and
the inject option for the directive controller injection was removed.
To migrate the code follow the example below:
Before:
scope: {
myAttr: 'attribute',
myBind: 'bind',
myExpression: 'expression',
myEval: 'evaluate',
myAccessor: 'accessor'
}
After:
scope: {
myAttr: '@',
myBind: '@',
myExpression: '&',
// myEval - usually not useful, but in cases where the expression is assignable, you can use '='
myAccessor: '=' // in directive's template change myAccessor() to myAccessor
}
The removed `inject` wasn't generaly useful for directives so there should be no code using it.
On IE9 the input event is not fired when backspace or delete key are pressed or when
cut is performed. This makes listening on the input event unreliable and therefore
it's better for us to just use keydown/change events instead.
Closes#879
It turns out that listening only on "blur" event is not sufficient in many scenarios,
especially when you use form validation you always had to use ngModelnstant
e.g. if you want to disable a button based on valid/invalid form.
The feedback we got from our apps as well as external apps is that the
ngModelInstant should be the default.
In the future we might provide alternative ways of suppressing updates
on each key stroke, but it's not going to be the default behavior.
Apps already using the ngModelInstant can safely remove it from their
templates. Input fields without ngModelInstant directive will start propagating
the input changes into the model on each key stroke.