Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
feat(mdChips): Add md-on-select expression support.
Browse files Browse the repository at this point in the history
Users want a way to be notified when a chip is selected.

fix #3413. closes #4088.
  • Loading branch information
topherfangio authored and ThomasBurleson committed Aug 14, 2015
1 parent 33815a7 commit 333984f
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 19 deletions.
23 changes: 20 additions & 3 deletions src/components/chips/chips.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ describe('<md-chips>', function() {
'<md-chips ng-model="items" md-on-append="appendChip($chip)"></md-chips>';
var CHIP_REMOVE_TEMPLATE =
'<md-chips ng-model="items" md-on-remove="removeChip($chip, $index)"></md-chips>';
var CHIP_SELECT_TEMPLATE =
'<md-chips ng-model="items" md-on-select="selectChip($chip)"></md-chips>';
var CHIP_READONLY_AUTOCOMPLETE_TEMPLATE =
'<md-chips ng-model="items" readonly="true">' +
' <md-autocomplete md-items="item in [\'hi\', \'ho\', \'he\']"></md-autocomplete>' +
Expand Down Expand Up @@ -134,6 +136,21 @@ describe('<md-chips>', function() {
});


it('should call the select method when selecting a chip', function() {
var element = buildChips(CHIP_SELECT_TEMPLATE);
var ctrl = element.controller('mdChips');

scope.selectChip = jasmine.createSpy('selectChip');

element.scope().$apply(function() {
ctrl.items = ['Grape'];
ctrl.selectChip(0);
});

expect(scope.selectChip).toHaveBeenCalled();
expect(scope.selectChip.calls.mostRecent().args[0]).toBe('Grape');
});

it('should handle appending an object chip', function() {
var element = buildChips(CHIP_APPEND_TEMPLATE);
var ctrl = element.controller('mdChips');
Expand Down Expand Up @@ -394,9 +411,9 @@ describe('<md-chips>', function() {
});
});

// *******************************
// Internal helper methods
// *******************************
// *******************************
// Internal helper methods
// *******************************

function buildChips(str) {
var container;
Expand Down
47 changes: 35 additions & 12 deletions src/components/chips/js/chipsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,18 @@ function MdChipsCtrl ($scope, $mdConstant, $log, $element, $timeout) {
this.chipBuffer = '';

/**
* Whether to use the mdOnAppend expression to transform the chip buffer
* Whether to use the onAppend expression to transform the chip buffer
* before appending it to the list.
* @type {boolean}
*/
this.useMdOnAppend = false;
this.useOnAppend = false;

/**
* Whether to use the onSelect expression to notify the component's user
* after selecting a chip from the list.
* @type {boolean}
*/
this.useOnSelect = false;
}

/**
Expand Down Expand Up @@ -181,8 +188,8 @@ MdChipsCtrl.prototype.getAdjacentChipIndex = function(index) {
* @param newChip
*/
MdChipsCtrl.prototype.appendChip = function(newChip) {
if (this.useMdOnAppend && this.mdOnAppend) {
newChip = this.mdOnAppend({'$chip': newChip});
if (this.useOnAppend && this.onAppend) {
newChip = this.onAppend({'$chip': newChip});
}
if (this.items.indexOf(newChip) + 1) return;
this.items.push(newChip);
Expand All @@ -191,23 +198,34 @@ MdChipsCtrl.prototype.appendChip = function(newChip) {
/**
* Sets whether to use the md-on-append expression. This expression is
* bound to scope and controller in {@code MdChipsDirective} as
* {@code mdOnAppend}. Due to the nature of directive scope bindings, the
* {@code onAppend}. 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.useMdOnAppendExpression = function() {
this.useMdOnAppend = true;
MdChipsCtrl.prototype.useOnAppendExpression = function() {
this.useOnAppend = 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
* {@code onRemove}. 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.useOnRemoveExpression = function() {
this.useOnRemove = true;
};

/*
* Sets whether to use the md-on-select expression. This expression is
* bound to scope and controller in {@code MdChipsDirective} as
* {@code onSelect}. 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;
MdChipsCtrl.prototype.useOnSelectExpression = function() {
this.useOnSelect = true;
};

/**
Expand Down Expand Up @@ -247,8 +265,8 @@ MdChipsCtrl.prototype.resetChipBuffer = function() {
MdChipsCtrl.prototype.removeChip = function(index) {
var removed = this.items.splice(index, 1);

if (removed && removed.length && this.useMdOnRemove && this.mdOnRemove) {
this.mdOnRemove({ '$chip': removed[0], '$index': index });
if (removed && removed.length && this.useOnRemove && this.onRemove) {
this.onRemove({ '$chip': removed[0], '$index': index });
}
};

Expand Down Expand Up @@ -280,6 +298,11 @@ MdChipsCtrl.prototype.selectAndFocusChipSafe = function(index) {
MdChipsCtrl.prototype.selectChip = function(index) {
if (index >= -1 && index <= this.items.length) {
this.selectedChip = index;

// Fire the onSelect if provided
if (this.useOnSelect && this.onSelect) {
this.onSelect({'$chip': this.items[this.selectedChip] });
}
} else {
this.$log.warn('Selected Chip index out of bounds; ignoring.');
}
Expand Down
14 changes: 10 additions & 4 deletions src/components/chips/js/chipsDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
* object when adding a chip.
* @param {expression} md-on-remove An expression which will be called when a chip has been
* removed.
* @param {expression} md-on-select An expression which will be called when a chip is selected.
* @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
Expand Down Expand Up @@ -162,8 +163,9 @@
readonly: '=readonly',
placeholder: '@',
secondaryPlaceholder: '@',
mdOnAppend: '&',
mdOnRemove: '&',
onAppend: '&mdOnAppend',
onRemove: '&mdOnRemove',
onSelect: '&mdOnSelect',
deleteHint: '@',
deleteButtonLabel: '@',
requireMatch: '=?mdRequireMatch'
Expand Down Expand Up @@ -245,11 +247,15 @@

// If an `md-on-append` attribute was set, tell the controller to use the expression
// when appending chips.
if (attrs.mdOnAppend) mdChipsCtrl.useMdOnAppendExpression();
if (attrs.mdOnAppend) mdChipsCtrl.useOnAppendExpression();

// If an `md-on-remove` attribute was set, tell the controller to use the expression
// when removing chips.
if (attrs.mdOnRemove) mdChipsCtrl.useMdOnRemoveExpression();
if (attrs.mdOnRemove) mdChipsCtrl.useOnRemoveExpression();

// If an `md-on-select` attribute was set, tell the controller to use the expression
// when selecting chips.
if (attrs.mdOnSelect) mdChipsCtrl.useOnSelectExpression();

// 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
Expand Down

0 comments on commit 333984f

Please sign in to comment.