From 3b19d2884646db007a0b30b3d2e8e6c31480ba91 Mon Sep 17 00:00:00 2001 From: aecepoglu Date: Tue, 13 Dec 2016 04:06:01 +0300 Subject: [PATCH] on-add, on-remove. Fixes #19 --- dist/angular-chips.js | 12 ++++++++- dist/angular-chips.min.js | 2 +- src/js/directives/chips.js | 12 ++++++++- test/basic_flow_spec.js | 1 - test/callback_spec.js | 54 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 test/callback_spec.js diff --git a/dist/angular-chips.js b/dist/angular-chips.js index d1946e1..ff0f7b8 100644 --- a/dist/angular-chips.js +++ b/dist/angular-chips.js @@ -127,6 +127,10 @@ scope.chips.list.push(data); model.add(data); } + + if (scope.onAdd) { + scope.onAdd({$chip: data}); + } }; scope.chips.deleteChip = function(index) { @@ -151,6 +155,10 @@ model.delete(index); } + if (scope.onRemove) { + scope.onRemove({$chip: deletedChip}); + } + return true; } @@ -256,7 +264,9 @@ * remove-chip="callback($chip)" * Call back method should return true to remove or false for nothing */ - removeChip: '&?' + removeChip: '&?', + onAdd: '&?', + onRemove: '&?' }, transclude: true, require: 'ngModel', diff --git a/dist/angular-chips.min.js b/dist/angular-chips.min.js index 90fd528..58e7ffe 100644 --- a/dist/angular-chips.min.js +++ b/dist/angular-chips.min.js @@ -1 +1 @@ -!function(){function e(e){return e&&angular.isFunction(e.then)}function i(e){return{add:function(i){var n=angular.copy(e.$modelValue)||[];n.push(i),e.$setViewValue(n)},"delete":function(i){var n=angular.copy(e.$modelValue);n.splice(i,1),e.$setViewValue(n)},deleteByValue:function(i){var n,t;for(n=0;n=o.chips.list.length)){var i=o.chips.list[e];if(!o.removeChip||o.removeChip({$chip:i}))return o.chips.list.splice(e,1),i.isFailed?void o.$apply():(i instanceof n?h.deleteByValue(i.defer):h["delete"](e),!0)}},s.$render=function(){if(f&&s.$modelValue){var e,i=[];for(e=0;e");var m=angular.element(o.chipTemplate);m.attr("ng-repeat","chip in chips.list track by $index"),m.attr("ng-class","{'chip-failed':chip.isFailed}"),m.attr("tabindex","-1"),m.attr("index","{{$index}}"),p.append(m);var C=r(p)(o);a.prepend(C),a.on("click",function(e){"CHIPS"===e.target.nodeName&&g.focus()}),o.chips.handleKeyDown=function(e){function i(i){var t,r=parseInt(e.target.getAttribute("index"));t=r>=0?r:n.length;var l=t+i;l<0?0===o.chips.list.length&&g.focus():l>=n.length?g.focus():n[l].focus()}var n=p.children();if(e.keyCode===l.BACKSPACE){var t=parseInt(e.target.getAttribute("index"));e.target===g&&""===e.target.value?i(-1):e.target.parentElement===p[0]&&o.chips.deleteChip(t)&&i(-1),e.preventDefault()}else e.keyCode===l.LEFT?i(-1):e.keyCode===l.RIGHT&&i(1)},a.on("keydown",o.chips.handleKeyDown),c(a).addClass("chip-out-focus")}return a.$inject=["scope","iElement","iAttrs","ngModelCtrl","transcludefn"],{restrict:"E",scope:{render:"&?",removeChip:"&?"},transclude:!0,require:"ngModel",link:a,controller:"chipsController",controllerAs:"chips",template:"
"}}function o(e,i,n){this.registerChild=function(i){if(e.chipTemplate)throw"should have only one chip-tmpl";e.chipTemplate=i},this.setFocus=function(e){e?n(i).removeClass("chip-out-focus").addClass("chip-in-focus"):n(i).removeClass("chip-in-focus").addClass("chip-out-focus")},this.removeChip=function(i,n){e.chips.deleteChip(n)}}r.$inject=["$compile","$timeout","DomUtil"],o.$inject=["$scope","$element","DomUtil"],angular.module("angular.chips",[]).directive("chips",r).controller("chipsController",o);var l={BACKSPACE:8,LEFT:37,RIGHT:39}}(),function(){function e(){return{require:"^^chips",transclude:!0,link:function(e,i,n,t,r){r(e,function(e){var n="";angular.forEach(e,function(e){n+=e.outerHTML||""}),t.registerChild(n),i.remove()})}}}angular.module("angular.chips").directive("chipTmpl",e)}(),function(){function e(){return{restrict:"A",require:"^?chips",link:function(e,i,n,t){function r(){"string"!=typeof e.chip&&e.chip.isLoading||t.removeChip(e.chip,e.$index)}i.on("click",function(){r()})}}}angular.module("angular.chips").directive("removeChipButton",e)}(),function(){function e(e){var i={};return i.addClass=function(n){return i.removeClass(e,n),e.attr("class",e.attr("class")+" "+n),i},i.removeClass=function(n){var t=e.attr("class").split(" "),r=t.indexOf(n);return r!==-1&&t.splice(r,1),e.attr("class",t.join(" ")),i},i}angular.module("angular.chips").factory("DomUtil",function(){return e})}(),function(){function e(){return{restrict:"A",require:"^chips",link:i}}function i(e,i,n,t){i.on("keypress",function(e){13===e.keyCode&&""!==e.target.value&&(t.addChip(e.target.value),e.target.value="",e.preventDefault())}),i.on("focus",function(){t.setFocus(!0)}),i.on("blur",function(){t.setFocus(!1)})}i.$inject=["scope","iElement","iAttrs","chipsCtrl"],angular.module("angular.chips").directive("chipControl",e)}(),function(){function e(){return{restrict:"A",require:["ngModel","^chips"],link:function(e,i,n,t){var r=t[0],o=t[1];r.$render=function(e){r.$modelValue&&(o.addChip(r.$modelValue),i.val(""))},i.on("focus",function(){o.setFocus(!0)}),i.on("blur",function(){o.setFocus(!1)})}}}angular.module("angular.chips").directive("ngModelControl",e)}(); \ No newline at end of file +!function(){function e(e){return e&&angular.isFunction(e.then)}function n(e){return{add:function(n){var i=angular.copy(e.$modelValue)||[];i.push(n),e.$setViewValue(i)},"delete":function(n){var i=angular.copy(e.$modelValue);i.splice(n,1),e.$setViewValue(i)},deleteByValue:function(n){var i,t;for(i=0;i=o.chips.list.length)){var n=o.chips.list[e];if(!o.removeChip||o.removeChip({$chip:n}))return o.chips.list.splice(e,1),n.isFailed?void o.$apply():(n instanceof i?h.deleteByValue(n.defer):h["delete"](e),o.onRemove&&o.onRemove({$chip:n}),!0)}},s.$render=function(){if(f&&s.$modelValue){var e,n=[];for(e=0;e");var m=angular.element(o.chipTemplate);m.attr("ng-repeat","chip in chips.list track by $index"),m.attr("ng-class","{'chip-failed':chip.isFailed}"),m.attr("tabindex","-1"),m.attr("index","{{$index}}"),p.append(m);var C=r(p)(o);a.prepend(C),a.on("click",function(e){"CHIPS"===e.target.nodeName&&g.focus()}),o.chips.handleKeyDown=function(e){function n(n){var t,r=parseInt(e.target.getAttribute("index"));t=r>=0?r:i.length;var c=t+n;c<0?0===o.chips.list.length&&g.focus():c>=i.length?g.focus():i[c].focus()}var i=p.children();if(e.keyCode===c.BACKSPACE){var t=parseInt(e.target.getAttribute("index"));e.target===g&&""===e.target.value?n(-1):e.target.parentElement===p[0]&&o.chips.deleteChip(t)&&n(-1),e.preventDefault()}else e.keyCode===c.LEFT?n(-1):e.keyCode===c.RIGHT&&n(1)},a.on("keydown",o.chips.handleKeyDown),l(a).addClass("chip-out-focus")}return a.$inject=["scope","iElement","iAttrs","ngModelCtrl","transcludefn"],{restrict:"E",scope:{render:"&?",removeChip:"&?",onAdd:"&?",onRemove:"&?"},transclude:!0,require:"ngModel",link:a,controller:"chipsController",controllerAs:"chips",template:"
"}}function o(e,n,i){this.registerChild=function(n){if(e.chipTemplate)throw"should have only one chip-tmpl";e.chipTemplate=n},this.setFocus=function(e){e?i(n).removeClass("chip-out-focus").addClass("chip-in-focus"):i(n).removeClass("chip-in-focus").addClass("chip-out-focus")},this.removeChip=function(n,i){e.chips.deleteChip(i)}}r.$inject=["$compile","$timeout","DomUtil"],o.$inject=["$scope","$element","DomUtil"],angular.module("angular.chips",[]).directive("chips",r).controller("chipsController",o);var c={BACKSPACE:8,LEFT:37,RIGHT:39}}(),function(){function e(){return{require:"^^chips",transclude:!0,link:function(e,n,i,t,r){r(e,function(e){var i="";angular.forEach(e,function(e){i+=e.outerHTML||""}),t.registerChild(i),n.remove()})}}}angular.module("angular.chips").directive("chipTmpl",e)}(),function(){function e(){return{restrict:"A",require:"^?chips",link:function(e,n,i,t){function r(){"string"!=typeof e.chip&&e.chip.isLoading||t.removeChip(e.chip,e.$index)}n.on("click",function(){r()})}}}angular.module("angular.chips").directive("removeChipButton",e)}(),function(){function e(e){var n={};return n.addClass=function(i){return n.removeClass(e,i),e.attr("class",e.attr("class")+" "+i),n},n.removeClass=function(i){var t=e.attr("class").split(" "),r=t.indexOf(i);return r!==-1&&t.splice(r,1),e.attr("class",t.join(" ")),n},n}angular.module("angular.chips").factory("DomUtil",function(){return e})}(),function(){function e(){return{restrict:"A",require:"^chips",link:n}}function n(e,n,i,t){n.on("keypress",function(e){13===e.keyCode&&""!==e.target.value&&(t.addChip(e.target.value),e.target.value="",e.preventDefault())}),n.on("focus",function(){t.setFocus(!0)}),n.on("blur",function(){t.setFocus(!1)})}n.$inject=["scope","iElement","iAttrs","chipsCtrl"],angular.module("angular.chips").directive("chipControl",e)}(),function(){function e(){return{restrict:"A",require:["ngModel","^chips"],link:function(e,n,i,t){var r=t[0],o=t[1];r.$render=function(e){r.$modelValue&&(o.addChip(r.$modelValue),n.val(""))},n.on("focus",function(){o.setFocus(!0)}),n.on("blur",function(){o.setFocus(!1)})}}}angular.module("angular.chips").directive("ngModelControl",e)}(); \ No newline at end of file diff --git a/src/js/directives/chips.js b/src/js/directives/chips.js index c0a2cb1..e4d8ee0 100644 --- a/src/js/directives/chips.js +++ b/src/js/directives/chips.js @@ -124,6 +124,10 @@ scope.chips.list.push(data); model.add(data); } + + if (scope.onAdd) { + scope.onAdd({$chip: data}); + } }; scope.chips.deleteChip = function(index) { @@ -148,6 +152,10 @@ model.delete(index); } + if (scope.onRemove) { + scope.onRemove({$chip: deletedChip}); + } + return true; } @@ -253,7 +261,9 @@ * remove-chip="callback($chip)" * Call back method should return true to remove or false for nothing */ - removeChip: '&?' + removeChip: '&?', + onAdd: '&?', + onRemove: '&?' }, transclude: true, require: 'ngModel', diff --git a/test/basic_flow_spec.js b/test/basic_flow_spec.js index 92b6788..c52d137 100644 --- a/test/basic_flow_spec.js +++ b/test/basic_flow_spec.js @@ -188,5 +188,4 @@ describe('Directive chips : Basic flow', function() { var fun = function() { compile(angular.element(str))(scope) }; expect(fun).toThrow('should have only one chip-tmpl'); }); - }); diff --git a/test/callback_spec.js b/test/callback_spec.js new file mode 100644 index 0000000..4da9336 --- /dev/null +++ b/test/callback_spec.js @@ -0,0 +1,54 @@ +'use strict'; + +describe('Directive chips : callbacks', function() { + + beforeEach(module('angular.chips')); + + var element, scope, compile, template, isolateScope, timeout; + var input; + + /*** Basic flow ***/ + + beforeEach(inject(function($rootScope, $injector) { + scope = $rootScope.$new(); + + scope.samples = ['Apple', 'Cisco', 'Verizon', 'Microsoft']; + + scope.addCallback = function(x, y) {}; + + scope.removeCallback = function(x, y) {}; + + compile = $injector.get('$compile'); + template = [ + '', + '', + '{{chip}}', + '', + '', + '' + ].join("\n"); + + element = angular.element(template); + compile(element)(scope); + scope.$digest(); + isolateScope = element.isolateScope(); + input = element.find('input')[0]; + })); + + it('calls on-add callback when new chip is added', function() { + spyOn(scope, 'addCallback'); + + isolateScope.chips.addChip('new-chip-value'); + + expect(scope.addCallback).toHaveBeenCalledWith('a string', 'new-chip-value'); + }); + + it('calls on-remove callback when a chip is removed', function() { + spyOn(scope, 'removeCallback'); + + isolateScope.chips.deleteChip(2); + + expect(scope.removeCallback).toHaveBeenCalledWith('another string', 'Verizon'); + }); +});