diff --git a/src/components/chips/chips.spec.js b/src/components/chips/chips.spec.js index 4c905e73a9c..c5df9967014 100644 --- a/src/components/chips/chips.spec.js +++ b/src/components/chips/chips.spec.js @@ -4,6 +4,8 @@ describe('', function() { ''; var CHIP_APPEND_TEMPLATE = ''; + var CHIP_REMOVE_TEMPLATE = + ''; beforeEach(module('material.components.chips', 'material.components.autocomplete')); beforeEach(inject(function ($rootScope) { @@ -106,6 +108,22 @@ describe('', function() { expect(scope.items[3]).toBe('GrapeGrape'); }); + it('should call the remove method when removing a chip', function() { + var element = buildChips(CHIP_REMOVE_TEMPLATE); + var ctrl = element.controller('mdChips'); + + scope.removeChip = jasmine.createSpy('removeChip'); + + element.scope().$apply(function() { + ctrl.items = ['Grape']; + ctrl.removeChip(0); + }); + + expect(scope.removeChip).toHaveBeenCalled(); + expect(scope.removeChip.calls.mostRecent().args[0]).toBe('Grape'); // Chip + expect(scope.removeChip.calls.mostRecent().args[1]).toBe(0); // Index + }); + it('should handle appending an object chip', function() { var element = buildChips(CHIP_APPEND_TEMPLATE); var ctrl = element.controller('mdChips'); diff --git a/src/components/chips/js/chipsController.js b/src/components/chips/js/chipsController.js index f2747520c65..c574d9669f3 100644 --- a/src/components/chips/js/chipsController.js +++ b/src/components/chips/js/chipsController.js @@ -199,6 +199,17 @@ MdChipsCtrl.prototype.useMdOnAppendExpression = function() { this.useMdOnAppend = true; }; +/** + * Sets whether to use the md-on-remove expression. This expression is + * bound to scope and controller in {@code MdChipsDirective} as + * {@code mdOnRemove}. Due to the nature of directive scope bindings, the + * controller cannot know on its own/from the scope whether an expression was + * actually provided. + */ +MdChipsCtrl.prototype.useMdOnRemoveExpression = function() { + this.useMdOnRemove = true; +}; + /** * Gets the input buffer. The input buffer can be the model bound to the * default input item {@code this.chipBuffer}, the {@code selectedItem} @@ -234,7 +245,11 @@ MdChipsCtrl.prototype.resetChipBuffer = function() { * @param index */ MdChipsCtrl.prototype.removeChip = function(index) { - this.items.splice(index, 1); + var removed = this.items.splice(index, 1); + + if (removed && removed.length && this.useMdOnRemove && this.mdOnRemove) { + this.mdOnRemove({ '$chip': removed[0], '$index': index }); + } }; MdChipsCtrl.prototype.removeChipAndFocusInput = function (index) { diff --git a/src/components/chips/js/chipsDirective.js b/src/components/chips/js/chipsDirective.js index b6fd6f31550..c4e23495aec 100644 --- a/src/components/chips/js/chipsDirective.js +++ b/src/components/chips/js/chipsDirective.js @@ -71,6 +71,8 @@ * the input and delete buttons * @param {expression} md-on-append An expression expected to convert the input string into an * object when adding a chip. + * @param {expression} md-on-remove An expression which will be called when a chip has been + * removed. * @param {string=} delete-hint A string read by screen readers instructing users that pressing * the delete key will remove the chip. * @param {string=} delete-button-label A label for the delete button. Also hidden and read by @@ -162,6 +164,7 @@ placeholder: '@', secondaryPlaceholder: '@', mdOnAppend: '&', + mdOnRemove: '&', deleteHint: '@', deleteButtonLabel: '@', requireMatch: '=?mdRequireMatch' @@ -245,6 +248,10 @@ // when appending chips. if (attrs.mdOnAppend) mdChipsCtrl.useMdOnAppendExpression(); + // If an `md-on-remove` attribute was set, tell the controller to use the expression + // when removing chips. + if (attrs.mdOnRemove) mdChipsCtrl.useMdOnRemoveExpression(); + // The md-autocomplete and input elements won't be compiled until after this directive // is complete (due to their nested nature). Wait a tick before looking for them to // configure the controller.