diff --git a/src/uiSelectMultipleDirective.js b/src/uiSelectMultipleDirective.js index dd1c89723..b1e997ec5 100644 --- a/src/uiSelectMultipleDirective.js +++ b/src/uiSelectMultipleDirective.js @@ -5,11 +5,28 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec controller: ['$scope','$timeout', function($scope, $timeout){ - var ctrl = this; - var $select = $scope.$select; + var ctrl = this, + $select = $scope.$select, + ngModel; + + //Wait for link fn to inject it + $scope.$evalAsync(function(){ ngModel = $scope.ngModel; }); ctrl.activeMatchIndex = -1; + ctrl.updateModel = function(){ + ngModel.$setViewValue(Date.now()); //Set timestamp as a unique string to force changes + ctrl.refreshComponent(); + }; + + ctrl.refreshComponent = function(){ + //Remove already selected items + //e.g. When user clicks on a selection, the selected array changes and + //the dropdown should remove that item + $select.refreshItems(); + $select.sizeSearchInput(); + }; + // Remove item from multiple select ctrl.removeChoice = function(index){ @@ -33,6 +50,8 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec }); }); + ctrl.updateModel(); + }; ctrl.getPlaceholder = function(){ @@ -48,9 +67,11 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec link: function(scope, element, attrs, ctrls) { var $select = ctrls[0]; - var ngModel = ctrls[1]; + var ngModel = scope.ngModel = ctrls[1]; var $selectMultiple = scope.$selectMultiple; + //$select.selected = raw selected objects (ignoring any property binding) + $select.multiple = true; $select.removeSelected = true; @@ -76,63 +97,49 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec var data = $select.parserResult.source (scope, { $select : {search:''}}), //Overwrite $search locals = {}, result; - if (data){ - var resultMultiple = []; - var checkFnMultiple = function(list, value){ - //if the list is empty add the value to the list - if (!list || !list.length){ - resultMultiple.unshift(value); - return true; + if (!data) return inputValue; + var resultMultiple = []; + var checkFnMultiple = function(list, value){ + if (!list || !list.length) return; + for (var p = list.length - 1; p >= 0; p--) { + locals[$select.parserResult.itemName] = list[p]; + result = $select.parserResult.modelMapper(scope, locals); + if($select.parserResult.trackByExp){ + var matches = /\.(.+)/.exec($select.parserResult.trackByExp); + if(matches.length>0 && result[matches[1]] == value[matches[1]]){ + resultMultiple.unshift(list[p]); + return true; + } } - for (var p = list.length - 1; p >= 0; p--) { - locals[$select.parserResult.itemName] = list[p]; - result = $select.parserResult.modelMapper(scope, locals); - if($select.parserResult.trackByExp){ - var matches = /\.(.+)/.exec($select.parserResult.trackByExp); - if(matches.length>0 && result[matches[1]] == value[matches[1]]){ - resultMultiple.unshift(list[p]); - return true; - } - } - if (result == value){ - resultMultiple.unshift(list[p]); - return true; - } + if (angular.equals(result,value)){ + resultMultiple.unshift(list[p]); + return true; } - return false; - }; - if (!inputValue) return resultMultiple; //If ngModel was undefined - for (var k = inputValue.length - 1; k >= 0; k--) { - if (!checkFnMultiple($select.selected, inputValue[k])){ - checkFnMultiple(data, inputValue[k]); + } + return false; + }; + if (!inputValue) return resultMultiple; //If ngModel was undefined + for (var k = inputValue.length - 1; k >= 0; k--) { + //Check model array of currently selected items + if (!checkFnMultiple($select.selected, inputValue[k])){ + //Check model array of all items available + if (!checkFnMultiple(data, inputValue[k])){ + //If not found on previous lists, just add it directly to resultMultiple + resultMultiple.unshift(inputValue[k]); } } - return resultMultiple; } - return inputValue; + return resultMultiple; }); - //Watch selection + //Watch for external model changes scope.$watchCollection(function(){ return ngModel.$modelValue; }, function(newValue, oldValue) { - if (oldValue != newValue) + if (oldValue != newValue){ ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters - }); - //TODO Should be a better way to detect first pass - $select.firstPass = true; // so the form doesn't get dirty as soon as it loads - scope.$watchCollection('$select.selected', function() { - if (!$select.firstPass) { - ngModel.$setViewValue(Date.now()); //Set timestamp as a unique string to force changes - } else { - $select.firstPass = false; + $selectMultiple.refreshComponent(); } - //Remove already selected items - //e.g. When user clicks on a selection, the selected array changes and - //the dropdown should remove that item - $select.refreshItems(); - //TODO Should add a test - $select.sizeSearchInput(); }); - + ngModel.$render = function() { // Make sure that model value is array if(!angular.isArray(ngModel.$viewValue)){ @@ -144,11 +151,12 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec } } $select.selected = ngModel.$viewValue; + scope.$evalAsync(); //To force $digest }; scope.$on('uis:select', function (event, item) { $select.selected.push(item); - $select.sizeSearchInput(); + $selectMultiple.updateModel(); }); scope.$on('uis:activate', function () {