Skip to content

Commit

Permalink
feat(chips): trigger ng-change on chip addition/removal (angular#11166)
Browse files Browse the repository at this point in the history
* Add test of `ng-change` for `md-chips`
* Add docs regarding `ng-change` for `md-chips` and `md-contact-chips`
* Add demo for ng-change on `md-chips`
* Add demo for ng-change on `md-contact-chips`

Closes angular#11161
Closes angular#3857
  • Loading branch information
chenlijun99 authored and andrewseguin committed Mar 23, 2018
1 parent 1ef9ec3 commit 19da42d
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 8 deletions.
25 changes: 24 additions & 1 deletion src/components/chips/chips.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ describe('<md-chips>', function() {
'<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_NG_CHANGE_TEMPLATE =
'<md-chips ng-model="items" ng-change="onModelChange(items)"></md-chips>';
var CHIP_READONLY_TEMPLATE =
'<md-chips ng-model="items" readonly="isReadonly"></md-chips>';
var CHIP_READONLY_AUTOCOMPLETE_TEMPLATE =
Expand Down Expand Up @@ -193,6 +195,27 @@ describe('<md-chips>', function() {
});


it('should trigger ng-change on chip addition/removal', function() {
var element = buildChips(CHIP_NG_CHANGE_TEMPLATE);
var ctrl = element.controller('mdChips');

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

element.scope().$apply(function() {
ctrl.chipBuffer = 'Melon';
simulateInputEnterKey(ctrl);
});
expect(scope.onModelChange).toHaveBeenCalled();
expect(scope.onModelChange.calls.mostRecent().args[0].length).toBe(4);

element.scope().$apply(function() {
ctrl.removeChip(0);
});
expect(scope.onModelChange).toHaveBeenCalled();
expect(scope.onModelChange.calls.mostRecent().args[0].length).toBe(3);
});


it('should call the select method when selecting a chip', function() {
var element = buildChips(CHIP_SELECT_TEMPLATE);
var ctrl = element.controller('mdChips');
Expand Down Expand Up @@ -1656,7 +1679,7 @@ describe('<md-chips>', function() {
return scope.fruits.filter(function(item) {
return item.toLowerCase().indexOf(searchText.toLowerCase()) === 0;
});
}
};
}

function simulateInputEnterKey(ctrl) {
Expand Down
5 changes: 5 additions & 0 deletions src/components/chips/demoBasicUsage/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ <h2 class="md-title">Use the default chip template.</h2>

<md-chips ng-model="ctrl.fruitNames" readonly="ctrl.readonly" md-removable="ctrl.removable"></md-chips>

<br/>
<h2 class="md-title">Use ng-change</h2>

<md-chips ng-model="ctrl.ngChangeFruitNames" ng-change="ctrl.onModelChange(ctrl.ngChangeFruitNames)"
md-removable="ctrl.removable"></md-chips>

<br/>
<h2 class="md-title">Make chips editable.</h2>
Expand Down
5 changes: 5 additions & 0 deletions src/components/chips/demoBasicUsage/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

// Lists of fruit names and Vegetable objects
self.fruitNames = ['Apple', 'Banana', 'Orange'];
self.ngChangeFruitNames = angular.copy(self.fruitNames);
self.roFruitNames = angular.copy(self.fruitNames);
self.editableFruitNames = angular.copy(self.fruitNames);

Expand All @@ -39,5 +40,9 @@
type: 'unknown'
};
};

self.onModelChange = function(newModel) {
alert('The model has changed');
};
}
})();
1 change: 1 addition & 0 deletions src/components/chips/demoContactChips/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<md-content class="md-padding autocomplete" layout="column">
<md-contact-chips
ng-model="ctrl.contacts"
ng-change="ctrl.onModelChange(ctrl.contacts)"
md-contacts="ctrl.querySearch($query)"
md-contact-name="name"
md-contact-image="image"
Expand Down
5 changes: 5 additions & 0 deletions src/components/chips/demoContactChips/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

self.querySearch = querySearch;
self.delayedQuerySearch = delayedQuerySearch;
self.onModelChange = onModelChange;

/**
* Search for contacts; use a random delay to simulate a remote call
Expand Down Expand Up @@ -84,6 +85,10 @@

}

function onModelChange(model) {
alert('The model has changed');
}

function loadContacts() {
var contacts = [
'Marina Augustine',
Expand Down
17 changes: 10 additions & 7 deletions src/components/chips/js/chipsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ MdChipsCtrl.prototype.getCursorPosition = function(element) {
MdChipsCtrl.prototype.updateChipContents = function(chipIndex, chipContents){
if(chipIndex >= 0 && chipIndex < this.items.length) {
this.items[chipIndex] = chipContents;
this.ngModelCtrl.$setDirty();
this.updateNgModel();
}
};

Expand Down Expand Up @@ -484,9 +484,7 @@ MdChipsCtrl.prototype.appendChip = function(newChip) {
var length = this.items.push(newChip);
var index = length - 1;

// Update model validation
this.ngModelCtrl.$setDirty();
this.validateModel();
this.updateNgModel();

// If they provide the md-on-add attribute, notify them of the chip addition
if (this.useOnAdd && this.onAdd) {
Expand Down Expand Up @@ -585,16 +583,21 @@ MdChipsCtrl.prototype.validateModel = function() {
this.ngModelCtrl.$validate(); // rerun any registered validators
};

MdChipsCtrl.prototype.updateNgModel = function() {
this.ngModelCtrl.$setViewValue(this.items.slice());
// TODO add the md-max-chips validator to this.ngModelCtrl.validators so that
// the validation will be performed automatically on $viewValue change
this.validateModel();
};

/**
* Removes the chip at the given index.
* @param index
*/
MdChipsCtrl.prototype.removeChip = function(index) {
var removed = this.items.splice(index, 1);

// Update model validation
this.ngModelCtrl.$setDirty();
this.validateModel();
this.updateNgModel();

if (removed && removed.length && this.useOnRemove && this.onRemove) {
this.onRemove({ '$chip': removed[0], '$index': index });
Expand Down
1 change: 1 addition & 0 deletions src/components/chips/js/chipsDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
* Please refer to the documentation of this option (below) for more information.
*
* @param {string=|object=} ng-model A model to which the list of items will be bound.
* @param {expression=} ng-change AngularJS expression to be executed on chip addition/removal
* @param {string=} placeholder Placeholder text that will be forwarded to the input.
* @param {string=} secondary-placeholder Placeholder text that will be forwarded to the input,
* displayed when there is at least one item in the list
Expand Down
3 changes: 3 additions & 0 deletions src/components/chips/js/contactChipsDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ angular
* appearance of the matched text inside of the contacts' autocomplete popup.
*
* @param {string=|object=} ng-model A model to bind the list of items to
* @param {expression=} ng-change AngularJS expression to be executed on chip addition/removal
* @param {string=} placeholder Placeholder text that will be forwarded to the input.
* @param {string=} secondary-placeholder Placeholder text that will be forwarded to the input,
* displayed when there is at least on item in the list
Expand Down Expand Up @@ -57,6 +58,7 @@ angular
var MD_CONTACT_CHIPS_TEMPLATE = '\
<md-chips class="md-contact-chips"\
ng-model="$mdContactChipsCtrl.contacts"\
ng-change="$mdContactChipsCtrl.ngChange($mdContactChipsCtrl.contacts)"\
md-require-match="$mdContactChipsCtrl.requireMatch"\
md-chip-append-delay="{{$mdContactChipsCtrl.chipAppendDelay}}" \
md-autocomplete-snap>\
Expand Down Expand Up @@ -122,6 +124,7 @@ function MdContactChips($mdTheming, $mdUtil) {
contactImage: '@mdContactImage',
contactEmail: '@mdContactEmail',
contacts: '=ngModel',
ngChange: '&',
requireMatch: '=?mdRequireMatch',
minLength: '=?mdMinLength',
highlightFlags: '@?mdHighlightFlags',
Expand Down

0 comments on commit 19da42d

Please sign in to comment.