diff --git a/dist/select.js b/dist/select.js index 3dd469ca5..41de619f2 100644 --- a/dist/select.js +++ b/dist/select.js @@ -101,6 +101,7 @@ angular.module('ui.select', []) ctrl.selected = undefined; ctrl.open = false; ctrl.disabled = false; + ctrl.allowNewValues = false; ctrl.searchInput = $element.querySelectorAll('input.ui-select-search'); @@ -151,6 +152,10 @@ angular.module('ui.select', []) // When the user clicks on an item inside the dropdown list ctrl.select = function(item) { + if(ctrl.allowNewValues && !item && ctrl.search.length > 0) { + // create new item on the fly + item = ctrl.search; + } ctrl.selected = item; ctrl.close(); // Using a watch instead of $scope.ngModel.$setViewValue(item) @@ -220,6 +225,8 @@ angular.module('ui.select', []) attrs.$observe('disabled', function() { $select.disabled = attrs.disabled ? true : false; }); + + $select.allowNewValues = attrs.allowNewValues ? true : false; scope.$watch('$select.selected', function(newValue, oldValue) { if (ngModel.$viewValue !== newValue) { @@ -236,13 +243,15 @@ angular.module('ui.select', []) var rows = container.querySelectorAll('.ui-select-choices-row'); var highlighted = rows[$select.activeIndex]; - var posY = highlighted.offsetTop + highlighted.clientHeight - container[0].scrollTop; - var height = container[0].offsetHeight; - - if (posY > height) { - container[0].scrollTop += posY - height; - } else if (posY < highlighted.clientHeight) { - container[0].scrollTop -= highlighted.clientHeight - posY; + if(highlighted) { + var posY = highlighted.offsetTop + highlighted.clientHeight - container[0].scrollTop; + var height = container[0].offsetHeight; + + if (posY > height) { + container[0].scrollTop += posY - height; + } else if (posY < highlighted.clientHeight) { + container[0].scrollTop -= highlighted.clientHeight - posY; + } } } @@ -326,7 +335,8 @@ angular.module('ui.select', []) $select.parseRepeatAttr(attrs.repeat); scope.$watch('$select.search', function() { - $select.activeIndex = 0; + // do not autoselect first value if new values are allowed + $select.activeIndex = $select.allowNewValues ? -1 : 0; $select.populateItems(attrs.repeat); }); }; diff --git a/src/select.js b/src/select.js index c89cca41d..a59bf6cdc 100644 --- a/src/select.js +++ b/src/select.js @@ -101,6 +101,7 @@ angular.module('ui.select', []) ctrl.selected = undefined; ctrl.open = false; ctrl.disabled = false; + ctrl.allowNewValues = false; ctrl.searchInput = $element.querySelectorAll('input.ui-select-search'); @@ -151,6 +152,10 @@ angular.module('ui.select', []) // When the user clicks on an item inside the dropdown list ctrl.select = function(item) { + if(ctrl.allowNewValues && !item && ctrl.search.length > 0) { + // create new item on the fly + item = ctrl.search; + } ctrl.selected = item; ctrl.close(); // Using a watch instead of $scope.ngModel.$setViewValue(item) @@ -220,6 +225,8 @@ angular.module('ui.select', []) attrs.$observe('disabled', function() { $select.disabled = attrs.disabled ? true : false; }); + + $select.allowNewValues = attrs.allowNewValues ? true : false; scope.$watch('$select.selected', function(newValue, oldValue) { if (ngModel.$viewValue !== newValue) { @@ -236,13 +243,15 @@ angular.module('ui.select', []) var rows = container.querySelectorAll('.ui-select-choices-row'); var highlighted = rows[$select.activeIndex]; - var posY = highlighted.offsetTop + highlighted.clientHeight - container[0].scrollTop; - var height = container[0].offsetHeight; - - if (posY > height) { - container[0].scrollTop += posY - height; - } else if (posY < highlighted.clientHeight) { - container[0].scrollTop -= highlighted.clientHeight - posY; + if(highlighted) { + var posY = highlighted.offsetTop + highlighted.clientHeight - container[0].scrollTop; + var height = container[0].offsetHeight; + + if (posY > height) { + container[0].scrollTop += posY - height; + } else if (posY < highlighted.clientHeight) { + container[0].scrollTop -= highlighted.clientHeight - posY; + } } } @@ -326,7 +335,8 @@ angular.module('ui.select', []) $select.parseRepeatAttr(attrs.repeat); scope.$watch('$select.search', function() { - $select.activeIndex = 0; + // do not autoselect first value if new values are allowed + $select.activeIndex = $select.allowNewValues ? -1 : 0; $select.populateItems(attrs.repeat); }); }; diff --git a/test/select.spec.js b/test/select.spec.js index 44095a6c1..c51987f31 100644 --- a/test/select.spec.js +++ b/test/select.spec.js @@ -19,6 +19,17 @@ describe('ui-select tests', function() { { name: 'Nicole', email: 'nicole@email.com', age: 43 }, { name: 'Adrian', email: 'adrian@email.com', age: 21 } ]; + + scope.names = [ + 'Adam', + 'Amalie', + 'Wladimir', + 'Samantha', + 'Estefanía', + 'Natasha', + 'Nicole', + 'Adrian' + ]; })); @@ -30,15 +41,30 @@ describe('ui-select tests', function() { return el; } - function createUiSelect(attrs) { + function generateAttrsHtml(attrs) { var attrsHtml = ''; if (attrs !== undefined) { if (attrs.disabled !== undefined) { attrsHtml += ' ng-disabled="' + attrs.disabled + '"'; } if (attrs.required !== undefined) { attrsHtml += ' ng-required="' + attrs.required + '"'; } + if (attrs.allowNewValues !== undefined) { attrsHtml += ' allow-new-values="' + attrs.allowNewValues + '"'; } } + return attrsHtml; + } + function createUiSelectCollection(attrs) { return compileTemplate( - ' \ + ' \ + {{$select.selected}} \ + \ +
\ +
\ +
' + ); + } + + function createUiSelect(attrs) { + return compileTemplate( + ' \ {{$select.selected.name}} \ \
\ @@ -159,6 +185,15 @@ describe('ui-select tests', function() { clickMatch(el3); expect(el3.scope().$select.open).toEqual(true); }); + + it('should allow new values if the attribute says so', function() { + var el = createUiSelectCollection({allowNewValues: true}); + clickMatch(el); + + $(el).scope().$select.select("I don't exist"); + + expect($(el).scope().$select.selected).toEqual("I don't exist"); + }); // See when an item that evaluates to false (such as "false" or "no") is selected, the placeholder is shown https://github.com/angular-ui/ui-select/pull/32 it('should not display the placeholder when item evaluates to false', function() {