diff --git a/README.md b/README.md index 6047cb7c..c0de000b 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ It expects the returned results from remote API to have a root object. In the ab | field-required-class | Set custom class name for required. | No | @ | "match" | | text-searching | Custom string to show when search is in progress. Set this to 'false' prevents text to show up. | No | @ | "Searching for items..." | | text-no-results | Custom string to show when there is no match. Set this to 'false' prevents text to show up. | No | @ | "Not found" | +| no-result-selected | A callback function called when user clicks on drop down 'No results found' item. | No | = | noResultSelectedFn | | initial-value | Initial value for component. If string, the internal model is set to the string value, if an object, the title-field attribute is used to parse the correct title for the view, and the internal model is set to the object. [example](https://ghiden.github.io/angucomplete-alt/#example9) | No | = | myInitialValue (object/string) | | input-changed | A callback function that is called when input field is changed. To get attributes of the input from which the assignment was made, use this.$parent.$index within your function. [example](https://ghiden.github.io/angucomplete-alt/#example10) | No | = | inputChangedFn | | auto-match | Allows for auto selecting an item if the search text matches a search results attributes exactly. [example](https://ghiden.github.io/angucomplete-alt/#example11) | No | @ | true | diff --git a/angucomplete-alt.js b/angucomplete-alt.js index f9fdf83d..adf18ac1 100644 --- a/angucomplete-alt.js +++ b/angucomplete-alt.js @@ -49,7 +49,7 @@ ' ' + '
' + '
' + - '
' + + '
' + '
' + '
' + ' ' + @@ -704,6 +704,13 @@ clearResults(); }; + scope.selectNoResult = function() { + if (typeof scope.noResultSelected === 'function') { + scope.noResultSelected(); + clearResults(); + } + }; + scope.inputChangeHandler = function(str) { if (str.length < minlength) { cancelHttpRequest(); @@ -821,7 +828,8 @@ fieldTabindex: '@', inputName: '@', focusFirst: '@', - parseInput: '&' + parseInput: '&', + noResultSelected: '=' }, templateUrl: function(element, attrs) { return attrs.templateUrl || TEMPLATE_URL; diff --git a/dist/angucomplete-alt.min.js b/dist/angucomplete-alt.min.js index d83180b8..0898c1fd 100644 --- a/dist/angucomplete-alt.min.js +++ b/dist/angucomplete-alt.min.js @@ -1,2 +1,2 @@ /*! Copyright (c) 2014 Hidenari Nozaki and contributors | Licensed under the MIT license */ -!function(a,b){"use strict";"undefined"!=typeof module&&module.exports?module.exports=b(require("angular")):"function"==typeof define&&define.amd?define(["angular"],b):b(a.angular)}(window,function(a){"use strict";a.module("angucomplete-alt",[]).directive("angucompleteAlt",["$q","$parse","$http","$sce","$timeout","$templateCache","$interpolate",function(a,b,c,d,e,f,g){function h(b,f,g,h){function w(a,c){a&&("object"==typeof a?(b.searchStr=C(a),z({originalObject:a})):"string"==typeof a&&a.length>0?b.searchStr=a:console&&console.error&&console.error("Tried to set "+(c?"initial":"")+" value of angucomplete to",a,"which is an invalid value"),F(!0))}function x(a){na=null,b.hideResults(a),document.body.removeEventListener("click",x)}function y(a){return a.which?a.which:a.keyCode}function z(a){"function"==typeof b.selectedObject?b.selectedObject(a,b.selectedObjectData):b.selectedObject=a,F(a?!0:!1)}function A(a){return function(c){return b[a]?b[a](c):c}}function B(a){z({originalObject:a}),b.clearSelected&&(b.searchStr=null),U()}function C(a){return b.titleField.split(",").map(function(b){return D(a,b)}).join(" ")}function D(a,b){var c,d;if(b){c=b.split("."),d=a;for(var e=0;e'+f[0]+""):a,d.trustAsHtml(e)}function F(a){b.notEmpty=a,ia=b.searchStr,b.fieldRequired&&h&&b.inputName&&h[b.inputName].$setValidity(ha,a)}function G(a){var c=y(a);if(c!==l&&c!==j)if(c===k||c===n)a.preventDefault();else if(c===i)a.preventDefault(),!b.showDropdown&&b.searchStr&&b.searchStr.length>=fa&&(V(),b.searching=!0,Y(b.searchStr));else if(c===m)U(),b.$apply(function(){ea.val(b.searchStr)});else{if(0===fa&&!b.searchStr)return;b.searchStr&&""!==b.searchStr?b.searchStr.length>=fa&&(V(),ga&&e.cancel(ga),b.searching=!0,ga=e(function(){Y(b.searchStr)},b.pause)):b.showDropdown=!1,ia&&ia!==b.searchStr&&!b.clearSelected&&b.$apply(function(){z()})}}function H(a){!b.overrideSuggestions||b.selectedObject&&b.selectedObject.originalObject===b.searchStr||(a&&a.preventDefault(),e.cancel(ga),R(),B(b.searchStr))}function I(a){var b=getComputedStyle(a);return a.offsetHeight+parseInt(b.marginTop,10)+parseInt(b.marginBottom,10)}function J(){return la.getBoundingClientRect().top+parseInt(getComputedStyle(la).maxHeight,10)}function K(){return f[0].querySelectorAll(".angucomplete-row")[b.currentIndex]}function L(){return K().getBoundingClientRect().top-(la.getBoundingClientRect().top+parseInt(getComputedStyle(la).paddingTop,10))}function M(a){la.scrollTop=la.scrollTop+a}function N(){var a=b.results[b.currentIndex];b.matchClass?ea.val(C(a.originalObject)):ea.val(a.title)}function O(a){var c=y(a),d=null,e=null;c===n&&b.results?(b.currentIndex>=0&&b.currentIndex=1?(b.$apply(function(){b.currentIndex--,N()}),ma&&(e=L(),e<0&&M(e-1))):0===b.currentIndex&&b.$apply(function(){b.currentIndex=-1,ea.val(b.searchStr)})):c===o?b.results&&b.results.length>0&&b.showDropdown?b.currentIndex===-1&&b.overrideSuggestions?H():(b.currentIndex===-1&&(b.currentIndex=0),b.selectResult(b.results[b.currentIndex]),b.$digest()):b.searchStr&&b.searchStr.length>0&&H():c===m&&a.preventDefault()}function P(a){return function(c,d,e,f){d||e||f||!c.data||(c=c.data),b.searching=!1,Z(D(aa(c),b.remoteUrlDataField),a)}}function Q(a,c,d,e){b.searching=ka,c||d||e||(c=a.status),0!==c&&c!==-1&&(b.remoteUrlErrorCallback?b.remoteUrlErrorCallback(a,c,d,e):console&&console.error&&console.error("http error"))}function R(){ja&&ja.resolve()}function S(d){var e={},f=b.remoteUrl+encodeURIComponent(d);b.remoteUrlRequestFormatter&&(e={params:b.remoteUrlRequestFormatter(d)},f=b.remoteUrl),b.remoteUrlRequestWithCredentials&&(e.withCredentials=!0),R(),ja=a.defer(),e.timeout=ja.promise,ka=!0,c.get(f,e).then(P(d)).catch(Q).finally(function(){ka=!1})}function T(c){R(),ja=a.defer(),b.remoteApiHandler(c,ja.promise).then(P(c)).catch(Q)}function U(){b.showDropdown=!1,b.results=[],la&&(la.scrollTop=0)}function V(){b.showDropdown=ca,b.currentIndex=b.focusFirst?0:-1,b.results=[]}function W(a){var c,d,e,f,g=b.searchFields.split(","),h=[];for("undefined"!=typeof b.parseInput()&&(a=b.parseInput()(a)),c=0;c=0;d&&(h[h.length]=b.localData[c])}return h}function X(a,c,d){if(!d)return!1;for(var e in c)if(c[e].toLowerCase()===d.toLowerCase())return b.selectResult(a),!0;return!1}function Y(a){!a||a.length0)for(b.results=[],d=0;d=0)?na=null:(_=e(function(){U(),b.$apply(function(){b.searchStr&&b.searchStr.length>0&&ea.val(b.searchStr)})},s),R(),b.focusOut&&b.focusOut(),b.overrideSuggestions&&b.searchStr&&b.searchStr.length>0&&b.currentIndex===-1&&H())},b.resetHideResults=function(){_&&e.cancel(_)},b.hoverRow=function(a){b.currentIndex=a},b.selectResult=function(a){b.matchClass&&(a.title=C(a.originalObject),a.description=D(a.originalObject,b.descriptionField)),b.clearSelected?b.searchStr=null:b.searchStr=a.title,z(a),U()},b.inputChangeHandler=function(a){return a.length
{{ result.title }}
{{result.description}}
'),{restrict:"EA",require:"^?form",scope:{selectedObject:"=",selectedObjectData:"=",disableInput:"=",initialValue:"=",localData:"=",localSearch:"&",remoteUrlRequestFormatter:"=",remoteUrlRequestWithCredentials:"@",remoteUrlResponseFormatter:"=",remoteUrlErrorCallback:"=",remoteApiHandler:"=",id:"@",type:"@",placeholder:"@",textSearching:"@",textNoResults:"@",remoteUrl:"@",remoteUrlDataField:"@",titleField:"@",descriptionField:"@",imageField:"@",inputClass:"@",pause:"@",searchFields:"@",minlength:"@",matchClass:"@",clearSelected:"@",overrideSuggestions:"@",fieldRequired:"=",fieldRequiredClass:"@",inputChanged:"=",autoMatch:"@",focusOut:"&",focusIn:"&",fieldTabindex:"@",inputName:"@",focusFirst:"@",parseInput:"&"},templateUrl:function(a,b){return b.templateUrl||w},compile:function(a){var b=g.startSymbol(),c=g.endSymbol();if("{{"!==b||"}}"!==c){var d=a.html().replace(/\{\{/g,b).replace(/\}\}/g,c);a.html(d)}return h}}}])}); \ No newline at end of file +!function(a,b){"use strict";"undefined"!=typeof module&&module.exports?module.exports=b(require("angular")):"function"==typeof define&&define.amd?define(["angular"],b):b(a.angular)}(window,function(a){"use strict";a.module("angucomplete-alt",[]).directive("angucompleteAlt",["$q","$parse","$http","$sce","$timeout","$templateCache","$interpolate",function(a,b,c,d,e,f,g){function h(b,f,g,h){function w(a,c){a&&("object"==typeof a?(b.searchStr=C(a),z({originalObject:a})):"string"==typeof a&&a.length>0?b.searchStr=a:console&&console.error&&console.error("Tried to set "+(c?"initial":"")+" value of angucomplete to",a,"which is an invalid value"),F(!0))}function x(a){na=null,b.hideResults(a),document.body.removeEventListener("click",x)}function y(a){return a.which?a.which:a.keyCode}function z(a){"function"==typeof b.selectedObject?b.selectedObject(a,b.selectedObjectData):b.selectedObject=a,F(a?!0:!1)}function A(a){return function(c){return b[a]?b[a](c):c}}function B(a){z({originalObject:a}),b.clearSelected&&(b.searchStr=null),U()}function C(a){return b.titleField.split(",").map(function(b){return D(a,b)}).join(" ")}function D(a,b){var c,d;if(b){c=b.split("."),d=a;for(var e=0;e'+f[0]+""):a,d.trustAsHtml(e)}function F(a){b.notEmpty=a,ia=b.searchStr,b.fieldRequired&&h&&b.inputName&&h[b.inputName].$setValidity(ha,a)}function G(a){var c=y(a);if(c!==l&&c!==j)if(c===k||c===n)a.preventDefault();else if(c===i)a.preventDefault(),!b.showDropdown&&b.searchStr&&b.searchStr.length>=fa&&(V(),b.searching=!0,Y(b.searchStr));else if(c===m)U(),b.$apply(function(){ea.val(b.searchStr)});else{if(0===fa&&!b.searchStr)return;b.searchStr&&""!==b.searchStr?b.searchStr.length>=fa&&(V(),ga&&e.cancel(ga),b.searching=!0,ga=e(function(){Y(b.searchStr)},b.pause)):b.showDropdown=!1,ia&&ia!==b.searchStr&&!b.clearSelected&&b.$apply(function(){z()})}}function H(a){!b.overrideSuggestions||b.selectedObject&&b.selectedObject.originalObject===b.searchStr||(a&&a.preventDefault(),e.cancel(ga),R(),B(b.searchStr))}function I(a){var b=getComputedStyle(a);return a.offsetHeight+parseInt(b.marginTop,10)+parseInt(b.marginBottom,10)}function J(){return la.getBoundingClientRect().top+parseInt(getComputedStyle(la).maxHeight,10)}function K(){return f[0].querySelectorAll(".angucomplete-row")[b.currentIndex]}function L(){return K().getBoundingClientRect().top-(la.getBoundingClientRect().top+parseInt(getComputedStyle(la).paddingTop,10))}function M(a){la.scrollTop=la.scrollTop+a}function N(){var a=b.results[b.currentIndex];b.matchClass?ea.val(C(a.originalObject)):ea.val(a.title)}function O(a){var c=y(a),d=null,e=null;c===n&&b.results?(b.currentIndex>=0&&b.currentIndex=1?(b.$apply(function(){b.currentIndex--,N()}),ma&&(e=L())<0&&M(e-1)):0===b.currentIndex&&b.$apply(function(){b.currentIndex=-1,ea.val(b.searchStr)})):c===o?b.results&&b.results.length>0&&b.showDropdown?-1===b.currentIndex&&b.overrideSuggestions?H():(-1===b.currentIndex&&(b.currentIndex=0),b.selectResult(b.results[b.currentIndex]),b.$digest()):b.searchStr&&b.searchStr.length>0&&H():c===m&&a.preventDefault()}function P(a){return function(c,d,e,f){d||e||f||!c.data||(c=c.data),b.searching=!1,Z(D(aa(c),b.remoteUrlDataField),a)}}function Q(a,c,d,e){b.searching=ka,c||d||e||(c=a.status),0!==c&&-1!==c&&(b.remoteUrlErrorCallback?b.remoteUrlErrorCallback(a,c,d,e):console&&console.error&&console.error("http error"))}function R(){ja&&ja.resolve()}function S(d){var e={},f=b.remoteUrl+encodeURIComponent(d);b.remoteUrlRequestFormatter&&(e={params:b.remoteUrlRequestFormatter(d)},f=b.remoteUrl),b.remoteUrlRequestWithCredentials&&(e.withCredentials=!0),R(),ja=a.defer(),e.timeout=ja.promise,ka=!0,c.get(f,e).then(P(d)).catch(Q).finally(function(){ka=!1})}function T(c){R(),ja=a.defer(),b.remoteApiHandler(c,ja.promise).then(P(c)).catch(Q)}function U(){b.showDropdown=!1,b.results=[],la&&(la.scrollTop=0)}function V(){b.showDropdown=ca,b.currentIndex=b.focusFirst?0:-1,b.results=[]}function W(a){var c,d,e,f,g=b.searchFields.split(","),h=[];for(void 0!==b.parseInput()&&(a=b.parseInput()(a)),c=0;c=0;d&&(h[h.length]=b.localData[c])}return h}function X(a,c,d){if(!d)return!1;for(var e in c)if(c[e].toLowerCase()===d.toLowerCase())return b.selectResult(a),!0;return!1}function Y(a){!a||a.length0)for(b.results=[],d=0;d=0)?na=null:(_=e(function(){U(),b.$apply(function(){b.searchStr&&b.searchStr.length>0&&ea.val(b.searchStr)})},s),R(),b.focusOut&&b.focusOut(),b.overrideSuggestions&&b.searchStr&&b.searchStr.length>0&&-1===b.currentIndex&&H())},b.resetHideResults=function(){_&&e.cancel(_)},b.hoverRow=function(a){b.currentIndex=a},b.selectResult=function(a){b.matchClass&&(a.title=C(a.originalObject),a.description=D(a.originalObject,b.descriptionField)),b.clearSelected?b.searchStr=null:b.searchStr=a.title,z(a),U()},b.selectNoResult=function(){"function"==typeof b.noResultSelected&&(b.noResultSelected(),U())},b.inputChangeHandler=function(a){return a.length
{{ result.title }}
{{result.description}}
'),{restrict:"EA",require:"^?form",scope:{selectedObject:"=",selectedObjectData:"=",disableInput:"=",initialValue:"=",localData:"=",localSearch:"&",remoteUrlRequestFormatter:"=",remoteUrlRequestWithCredentials:"@",remoteUrlResponseFormatter:"=",remoteUrlErrorCallback:"=",remoteApiHandler:"=",id:"@",type:"@",placeholder:"@",textSearching:"@",textNoResults:"@",remoteUrl:"@",remoteUrlDataField:"@",titleField:"@",descriptionField:"@",imageField:"@",inputClass:"@",pause:"@",searchFields:"@",minlength:"@",matchClass:"@",clearSelected:"@",overrideSuggestions:"@",fieldRequired:"=",fieldRequiredClass:"@",inputChanged:"=",autoMatch:"@",focusOut:"&",focusIn:"&",fieldTabindex:"@",inputName:"@",focusFirst:"@",parseInput:"&",noResultSelected:"="},templateUrl:function(a,b){return b.templateUrl||w},compile:function(a){var b=g.startSymbol(),c=g.endSymbol();if("{{"!==b||"}}"!==c){var d=a.html().replace(/\{\{/g,b).replace(/\}\}/g,c);a.html(d)}return h}}}])}); \ No newline at end of file diff --git a/test/angucomplete-alt.spec.js b/test/angucomplete-alt.spec.js index ab2cd7f5..acc730dd 100644 --- a/test/angucomplete-alt.spec.js +++ b/test/angucomplete-alt.spec.js @@ -994,6 +994,39 @@ describe('angucomplete-alt', function() { }); }); + describe('noResultSelected callback', function() { + it('should call noResultSelected callback if given', function() { + var element = angular.element('
'); + var selected = false; + $scope.noResultSelected = function(value) { + selected = true; + }; + $scope.countries = [ + {name: 'Afghanistan', code: 'AF'}, + {name: 'Aland Islands', code: 'AX'}, + {name: 'Albania', code: 'AL'} + ]; + $compile(element)($scope); + $scope.$digest(); + + expect(selected).toBe(false); + var inputField = element.find('#ex1_value'); + var eKeyup = $.Event('keyup'); + eKeyup.which = 122; // letter: z + + inputField.val('z'); + inputField.trigger('input'); + inputField.trigger(eKeyup); + $timeout.flush(); + expect(element.find('#ex1_dropdown').length).toBe(1); + + var dropDown = element.find('.angucomplete-searching[ng-bind="textNoResults"]'); + var eClick = $.Event('click'); + dropDown.trigger(eClick); + expect(selected).toBe(true); + }); + }); + describe('selectedObject callback with extra paramater', function() { it('should call selectedObject callback if given', function() { var element = angular.element('
');