From afd4bb49cc3dd4053438cfc436272f360e1a6fa8 Mon Sep 17 00:00:00 2001 From: Joel Hooks Date: Tue, 22 Apr 2014 16:20:39 -0500 Subject: [PATCH] ngModelOptions debounce was failing when specifying an event with a value of 0 Was testing ngModelOptions, and noticed that the provided example `ngModelOptions="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }"` didn't function. With a little investigating I determined that the logic operation was skipping debounce[trigger] if it was 0 (thanks JS falsiness!). My first solution was to do this: ```javascript var debounceDelay = ctrl.$options && ( isObject(ctrl.$options.debounce) ? (isNumber(ctrl.$options.debounce[trigger]) ? ctrl.$options.debounce[trigger] : (ctrl.$options.debounce['default'] || 0)) : ctrl.$options.debounce ) || 0; ``` Which hopefully makes us all cringe. Instead of adding this mess (the original logic took me about 30 minutes to understand), I decided to unroll it into something a bit less... terse. I added a unit test to cover this scenario. --- src/ng/directive/input.js | 21 +++++++++++++++++---- test/ng/directive/inputSpec.js | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 4a6a5827bd3c..82cbeb7a73bc 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -1822,10 +1822,23 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ * @param {string} trigger Event that triggered the update. */ this.$setViewValue = function(value, trigger) { - var debounceDelay = ctrl.$options && (isObject(ctrl.$options.debounce) - ? (ctrl.$options.debounce[trigger] || ctrl.$options.debounce['default'] || 0) - : ctrl.$options.debounce) || 0; - + var debounceDelay = 0, + options = ctrl.$options, + debounce; + + if(options && isDefined(options.debounce)) { + debounce = options.debounce; + if(isNumber(debounce)) { + debounceDelay = debounce; + } else if(isNumber(debounce[trigger])) { + debounceDelay = debounce[trigger]; + } else if (isNumber(debounce['default'])) { + debounceDelay = debounce['default']; + } else { + debounceDelay = 0; + } + } + $timeout.cancel(pendingDebounce); if (debounceDelay) { pendingDebounce = $timeout(function() { diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index e9b28f1e7464..3bef74bf0517 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -844,6 +844,25 @@ describe('input', function() { expect(scope.checkbox).toBe(false); })); + it('should allow selecting 0 for non-default debounce timeouts for each event on checkboxes', inject(function($timeout) { + compileInput(''); + + inputElm[0].checked = false; + browserTrigger(inputElm, 'click'); + expect(scope.checkbox).toBe(undefined); + $timeout.flush(8000); + expect(scope.checkbox).toBe(undefined); + $timeout.flush(3000); + expect(scope.checkbox).toBe(true); + inputElm[0].checked = true; + browserTrigger(inputElm, 'click'); + browserTrigger(inputElm, 'blur'); + $timeout.flush(0); + expect(scope.checkbox).toBe(false); + })); it('should inherit model update settings from ancestor elements', inject(function($timeout) { var doc = $compile(