From f711ec2a7984ee7fb08821d40a84fc78660c5c23 Mon Sep 17 00:00:00 2001 From: Andrei Varabei Date: Wed, 8 Feb 2017 10:36:39 -0500 Subject: [PATCH] fix(uiSelectMatch): set model value to `null` when cleared Closes #863 --- src/common.js | 4 ++++ src/uiSelectController.js | 6 ++--- src/uiSelectMultipleDirective.js | 10 ++++----- src/uiSelectSingleDirective.js | 16 +++++++++++--- test/select.spec.js | 38 +++++++++++++++++++++++++++----- 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/common.js b/src/common.js index 454c426bc..89848e57c 100644 --- a/src/common.js +++ b/src/common.js @@ -54,6 +54,10 @@ var KEY = { } }; +function isNil(value) { + return angular.isUndefined(value) || value === null; +} + /** * Add querySelectorAll() to jqLite. * diff --git a/src/uiSelectController.js b/src/uiSelectController.js index e86afe484..0d1c595eb 100644 --- a/src/uiSelectController.js +++ b/src/uiSelectController.js @@ -62,7 +62,7 @@ uis.controller('uiSelectCtrl', } ctrl.isEmpty = function() { - return angular.isUndefined(ctrl.selected) || ctrl.selected === null || ctrl.selected === '' || (ctrl.multiple && ctrl.selected.length === 0); + return isNil(ctrl.selected) || ctrl.selected === '' || (ctrl.multiple && ctrl.selected.length === 0); }; function _findIndex(collection, predicate, thisArg){ @@ -379,7 +379,7 @@ uis.controller('uiSelectCtrl', // When the user selects an item with ENTER or clicks the dropdown ctrl.select = function(item, skipFocusser, $event) { - if (item === undefined || !_isItemDisabled(item)) { + if (isNil(item) || !_isItemDisabled(item)) { if ( ! ctrl.items && ! ctrl.search && ! ctrl.tagging.isActivated) return; @@ -454,7 +454,7 @@ uis.controller('uiSelectCtrl', }; ctrl.clear = function($event) { - ctrl.select(undefined); + ctrl.select(null); $event.stopPropagation(); $timeout(function() { ctrl.focusser[0].focus(); diff --git a/src/uiSelectMultipleDirective.js b/src/uiSelectMultipleDirective.js index 1d0243724..629256fb1 100644 --- a/src/uiSelectMultipleDirective.js +++ b/src/uiSelectMultipleDirective.js @@ -162,7 +162,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec // Make sure that model value is array if(!angular.isArray(ngModel.$viewValue)){ // Have tolerance for null or undefined values - if(angular.isUndefined(ngModel.$viewValue) || ngModel.$viewValue === null){ + if (isNil(ngModel.$viewValue)){ ngModel.$viewValue = []; } else { throw uiSelectMinErr('multiarr', "Expected model value to be array but got '{0}'", ngModel.$viewValue); @@ -178,7 +178,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec return; } $select.selected.push(item); - var locals = {}; + var locals = {}; locals[$select.parserResult.itemName] = item; $timeout(function(){ @@ -261,11 +261,11 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec } else { return curr; } - + } else { // If nothing yet selected, select last item - return last; - } + return last; + } break; case KEY.DELETE: // Remove selected item and select next item diff --git a/src/uiSelectSingleDirective.js b/src/uiSelectSingleDirective.js index 4d001dad9..546f8aaad 100644 --- a/src/uiSelectSingleDirective.js +++ b/src/uiSelectSingleDirective.js @@ -9,6 +9,11 @@ uis.directive('uiSelectSingle', ['$timeout','$compile', function($timeout, $comp //From view --> model ngModel.$parsers.unshift(function (inputValue) { + // Keep original value for undefined and null + if (isNil(inputValue)) { + return inputValue; + } + var locals = {}, result; locals[$select.parserResult.itemName] = inputValue; @@ -18,6 +23,11 @@ uis.directive('uiSelectSingle', ['$timeout','$compile', function($timeout, $comp //From model --> view ngModel.$formatters.unshift(function (inputValue) { + // Keep original value for undefined and null + if (isNil(inputValue)) { + return inputValue; + } + var data = $select.parserResult && $select.parserResult.source (scope, { $select : {search:''}}), //Overwrite $search locals = {}, result; @@ -51,13 +61,13 @@ uis.directive('uiSelectSingle', ['$timeout','$compile', function($timeout, $comp scope.$on('uis:select', function (event, item) { $select.selected = item; - var locals = {}; + var locals = {}; locals[$select.parserResult.itemName] = item; - $timeout(function(){ + $timeout(function() { $select.onSelectCallback(scope, { $item: item, - $model: $select.parserResult.modelMapper(scope, locals) + $model: isNil(item) ? item : $select.parserResult.modelMapper(scope, locals) }); }); }); diff --git a/test/select.spec.js b/test/select.spec.js index 393cdc73b..5a2b16af1 100644 --- a/test/select.spec.js +++ b/test/select.spec.js @@ -15,6 +15,10 @@ describe('ui-select tests', function () { Escape: 27 }; + function isNil(value) { + return angular.isUndefined(value) || value === null; + } + //create a directive that wraps ui-select angular.module('wrapperDirective', ['ui.select']); angular.module('wrapperDirective').directive('wrapperUiSelect', function () { @@ -49,8 +53,8 @@ describe('ui-select tests', function () { restrict: 'A', require: 'ngModel', link: function (scope, element, attrs, ngModel) { - ngModel.$validators.testValidator = function (modelValue, viewValue) { - if (angular.isUndefined(modelValue) || modelValue === null) { + ngModel.$validators.testValidator = function(modelValue, viewValue) { + if (isNil(modelValue)) { return true; } else if (angular.isArray(modelValue)) { var allValid = true, idx = modelValue.length; @@ -611,11 +615,10 @@ describe('ui-select tests', function () { // Trigger clear. el.find('.select2-search-choice-close').click(); - expect(scope.selection.selected).toEqual(undefined); + expect(scope.selection.selected).toEqual(null); - // If there is no selection it the X icon should be gone. + // If there is no selection the X icon should be gone. expect(el.find('.select2-search-choice-close').length).toEqual(0); - }); it('should toggle allow-clear directive', function () { @@ -636,6 +639,31 @@ describe('ui-select tests', function () { expect(el.find('.select2-search-choice-close').length).toEqual(1); }); + it('should clear selection (with object as source)', function() { + var el = compileTemplate( + ' \ + {{$select.selected.value.name}} \ + \ +
\ +
\ +
\ +
' + ); + var $select = el.scope().$select; + + clickItem(el, 'Samantha'); + expect(scope.selection.selected).toEqual('Samantha'); + + // allowClear should be true. + expect($select.allowClear).toEqual(true); + + // Trigger clear. + el.find('.select2-search-choice-close').click(); + expect(scope.selection.selected).toEqual(null); + + // If there is no selection the X icon should be gone. + expect(el.find('.select2-search-choice-close').length).toEqual(0); + }); it('should pass tabindex to focusser', function () { var el = createUiSelect({tabindex: 5});