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

Ng model options fix #15401

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/ng/directive/ngModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
PENDING_CLASS: true,
addSetValidityMethod: true,
setupValidity: true,
$defaultModelOptions: false
defaultModelOptions: false
*/


Expand Down Expand Up @@ -245,7 +245,7 @@ function NgModelController($scope, $exceptionHandler, $attr, $element, $parse, $
this.$pending = undefined; // keep pending keys here
this.$name = $interpolate($attr.name || '', false)($scope);
this.$$parentForm = nullFormCtrl;
this.$options = $defaultModelOptions;
this.$options = defaultModelOptions;

this.$$parsedNgModel = $parse($attr.ngModel);
this.$$parsedNgModelAssign = this.$$parsedNgModel.assign;
Expand Down Expand Up @@ -818,7 +818,7 @@ NgModelController.prototype = {

this.$$timeout.cancel(this.$$pendingDebounce);
var that = this;
if (debounceDelay) {
if (debounceDelay > 0) { // this fails if debounceDelay is an object
this.$$pendingDebounce = this.$$timeout(function() {
that.$commitViewValue();
}, debounceDelay);
Expand Down
10 changes: 5 additions & 5 deletions src/ng/directive/ngModelOptions.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

/* exported $defaultModelOptions */
var $defaultModelOptions;
/* exported defaultModelOptions */
var defaultModelOptions;
var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;

/**
Expand Down Expand Up @@ -72,14 +72,14 @@ ModelOptions.prototype = {
}

// Finally add in any missing defaults
defaults(options, $defaultModelOptions.$$options);
defaults(options, defaultModelOptions.$$options);

return new ModelOptions(options);
}
};


$defaultModelOptions = new ModelOptions({
defaultModelOptions = new ModelOptions({
updateOn: '',
updateOnDefault: true,
debounce: 0,
Expand Down Expand Up @@ -335,7 +335,7 @@ var ngModelOptionsDirective = function() {
link: {
pre: function ngModelOptionsPreLinkFn(scope, element, attrs, ctrls) {
var optionsCtrl = ctrls[0];
var parentOptions = ctrls[1] ? ctrls[1].$options : $defaultModelOptions;
var parentOptions = ctrls[1] ? ctrls[1].$options : defaultModelOptions;
optionsCtrl.$options = parentOptions.createChild(scope.$eval(attrs.ngModelOptions));
}
}
Expand Down
70 changes: 48 additions & 22 deletions test/ng/directive/ngModelOptionsSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@

/* globals
generateInputCompilerHelper: false,
$defaultModelOptions: false
defaultModelOptions: false
*/
describe('ngModelOptions', function() {

describe('$defaultModelOptions', function() {
describe('defaultModelOptions', function() {
it('should provide default values', function() {
expect($defaultModelOptions.getOption('updateOn')).toEqual('');
expect($defaultModelOptions.getOption('updateOnDefault')).toEqual(true);
expect($defaultModelOptions.getOption('debounce')).toBe(0);
expect($defaultModelOptions.getOption('getterSetter')).toBe(false);
expect($defaultModelOptions.getOption('allowInvalid')).toBe(false);
expect($defaultModelOptions.getOption('timezone')).toBe(null);
expect(defaultModelOptions.getOption('updateOn')).toEqual('');
expect(defaultModelOptions.getOption('updateOnDefault')).toEqual(true);
expect(defaultModelOptions.getOption('debounce')).toBe(0);
expect(defaultModelOptions.getOption('getterSetter')).toBe(false);
expect(defaultModelOptions.getOption('allowInvalid')).toBe(false);
expect(defaultModelOptions.getOption('timezone')).toBe(null);
});
});

Expand All @@ -31,18 +31,18 @@ describe('ngModelOptions', function() {
}));


describe('should fall back to `$defaultModelOptions`', function() {
describe('should fall back to `defaultModelOptions`', function() {
it('if there is no `ngModelOptions` directive', function() {
var inputElm = helper.compileInput(
'<input type="text" ng-model="name" name="alias" />');

var inputOptions = $rootScope.form.alias.$options;
expect(inputOptions.getOption('updateOn')).toEqual($defaultModelOptions.getOption('updateOn'));
expect(inputOptions.getOption('updateOnDefault')).toEqual($defaultModelOptions.getOption('updateOnDefault'));
expect(inputOptions.getOption('debounce')).toEqual($defaultModelOptions.getOption('debounce'));
expect(inputOptions.getOption('getterSetter')).toEqual($defaultModelOptions.getOption('getterSetter'));
expect(inputOptions.getOption('allowInvalid')).toEqual($defaultModelOptions.getOption('allowInvalid'));
expect(inputOptions.getOption('timezone')).toEqual($defaultModelOptions.getOption('timezone'));
expect(inputOptions.getOption('updateOn')).toEqual(defaultModelOptions.getOption('updateOn'));
expect(inputOptions.getOption('updateOnDefault')).toEqual(defaultModelOptions.getOption('updateOnDefault'));
expect(inputOptions.getOption('debounce')).toEqual(defaultModelOptions.getOption('debounce'));
expect(inputOptions.getOption('getterSetter')).toEqual(defaultModelOptions.getOption('getterSetter'));
expect(inputOptions.getOption('allowInvalid')).toEqual(defaultModelOptions.getOption('allowInvalid'));
expect(inputOptions.getOption('timezone')).toEqual(defaultModelOptions.getOption('timezone'));
});


Expand All @@ -51,9 +51,9 @@ describe('ngModelOptions', function() {
'<input type="text" ng-model="name" name="alias" ng-model-options="{ updateOn: \'blur\' }"/>');

var inputOptions = $rootScope.form.alias.$options;
expect(inputOptions.getOption('debounce')).toEqual($defaultModelOptions.getOption('debounce'));
expect(inputOptions.getOption('debounce')).toEqual(defaultModelOptions.getOption('debounce'));
expect(inputOptions.getOption('updateOnDefault')).toBe(false);
expect(inputOptions.getOption('updateOnDefault')).not.toEqual($defaultModelOptions.getOption('updateOnDefault'));
expect(inputOptions.getOption('updateOnDefault')).not.toEqual(defaultModelOptions.getOption('updateOnDefault'));
});


Expand All @@ -63,9 +63,9 @@ describe('ngModelOptions', function() {
'</form>')($rootScope);
var inputOptions = $rootScope.form.alias.$options;

expect(inputOptions.getOption('debounce')).toEqual($defaultModelOptions.getOption('debounce'));
expect(inputOptions.getOption('debounce')).toEqual(defaultModelOptions.getOption('debounce'));
expect(inputOptions.getOption('updateOnDefault')).toBe(false);
expect(inputOptions.getOption('updateOnDefault')).not.toEqual($defaultModelOptions.getOption('updateOnDefault'));
expect(inputOptions.getOption('updateOnDefault')).not.toEqual(defaultModelOptions.getOption('updateOnDefault'));
dealoc(form);
});
});
Expand Down Expand Up @@ -469,26 +469,52 @@ describe('ngModelOptions', function() {
var inputElm = helper.compileInput(
'<input type="text" ng-model="name" name="alias" ' +
'ng-model-options="{' +
'updateOn: \'default blur\', ' +
'updateOn: \'default blur mouseup\', ' +
'debounce: { default: 10000, blur: 5000 }' +
'}"' +
'/>');

helper.changeInputValueTo('a');
expect($rootScope.checkbox).toBeUndefined();
expect($rootScope.name).toBeUndefined();
$timeout.flush(6000);
expect($rootScope.checkbox).toBeUndefined();
expect($rootScope.name).toBeUndefined();
$timeout.flush(4000);
expect($rootScope.name).toEqual('a');

helper.changeInputValueTo('b');
browserTrigger(inputElm, 'blur');
$timeout.flush(4000);
expect($rootScope.name).toEqual('a');
$timeout.flush(2000);
expect($rootScope.name).toEqual('b');

helper.changeInputValueTo('c');
browserTrigger(helper.inputElm, 'mouseup');
// counter-intuitively `default` in `debounce` is a catch-all
expect($rootScope.name).toEqual('b');
$timeout.flush(10000);
expect($rootScope.name).toEqual('c');
});


it('should trigger immediately for the event if not listed in the debounce list',
function() {
var inputElm = helper.compileInput(
'<input type="text" ng-model="name" name="alias" ' +
'ng-model-options="{' +
'updateOn: \'default blur foo\', ' +
'debounce: { blur: 5000 }' +
'}"' +
'/>');

helper.changeInputValueTo('a');
expect($rootScope.name).toEqual('a');

helper.changeInputValueTo('b');
browserTrigger(inputElm, 'foo');
expect($rootScope.name).toEqual('b');
});

it('should allow selecting different debounce timeouts for each event on checkboxes', function() {
var inputElm = helper.compileInput('<input type="checkbox" ng-model="checkbox" ' +
'ng-model-options="{ ' +
Expand Down