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

fix(chips): don't throw when chip models are recursive, complex objects #11535

Merged
merged 1 commit into from
Dec 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/chips/demoBasicUsage/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ <h2 class="md-title">Display an ordered set of objects as chips (with custom tem
<em>({{$chip.type}})</em>
</span>
</md-chip-template>
<button md-chip-remove class="md-primary vegetablechip">
<button md-chip-remove class="md-primary vegetablechip" aria-label="Remove {{$chip.name}}">
<md-icon md-svg-icon="md-close"></md-icon>
</button>
</md-chips>
Expand Down
29 changes: 22 additions & 7 deletions src/components/chips/js/chipRemoveDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,31 @@ angular
* @module material.components.chips
*
* @description
* Designates an element to be used as the delete button for a chip. <br/>
* This element is passed as a child of the `md-chips` element.
* Indicates that the associated element should be used as the delete button template for all chips.
* The associated element must be a child of `md-chips`.
*
* The designated button will be just appended to the chip and removes the given chip on click.<br/>
* By default the button is not being styled by the `md-chips` component.
* The provided button template will be appended to each chip and will remove the associated chip
* on click.
*
* The button is not styled or themed based on the theme set on the `md-chips` component. A theme
* class and custom icon can be specified in your template.
*
* You can also specify the `type` of the button in your template.
*
* @usage
* ### With Standard Chips
* <hljs lang="html">
* <md-chips ...>
* <button md-chip-remove class="md-primary" type="button" aria-label="Remove {{$chip}}">
* <md-icon md-svg-icon="md-close"></md-icon>
* </button>
* </md-chips>
* </hljs>
*
* ### With Object Chips
* <hljs lang="html">
* <md-chips>
* <button md-chip-remove="">
* <md-chips ...>
* <button md-chip-remove class="md-primary" type="button" aria-label="Remove {{$chip.name}}">
* <md-icon md-svg-icon="md-close"></md-icon>
* </button>
* </md-chips>
Expand Down Expand Up @@ -51,7 +66,7 @@ function MdChipRemove ($timeout) {
// Child elements aren't available until after a $timeout tick as they are hidden by an
// `ng-if`. see http://goo.gl/zIWfuw
$timeout(function() {
element.attr({ tabindex: -1, 'aria-hidden': true });
element.attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
element.find('button').attr('tabindex', '-1');
});
}
Expand Down
21 changes: 17 additions & 4 deletions src/components/chips/js/chipsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,18 @@ MdChipsCtrl.prototype.isEditingChip = function() {
return !!this.$element[0].querySelector('._md-chip-editing');
};

/**
* @param {string|Object} chip contents of a single chip
* @returns {boolean} true if the chip is an Object, false otherwise.
* @private
*/
MdChipsCtrl.prototype._isChipObject = function(chip) {
return angular.isObject(chip);
};

/**
* @returns {boolean} true if chips can be removed, false otherwise.
*/
MdChipsCtrl.prototype.isRemovable = function() {
// Return false if we have static chips
if (!this.ngModelCtrl) {
Expand Down Expand Up @@ -543,8 +554,8 @@ MdChipsCtrl.prototype.appendChip = function(newChip) {
}

// If items contains an identical object to newChip, do not append
if (angular.isObject(newChip)){
var identical = this.items.some(function(item){
if (angular.isObject(newChip)) {
var identical = this.items.some(function(item) {
return angular.equals(newChip, item);
});
if (identical) return;
Expand All @@ -560,7 +571,8 @@ MdChipsCtrl.prototype.appendChip = function(newChip) {
this.updateNgModel();

// Tell screen reader users that the chip was successfully added.
var chipContent = typeof newChip === 'object' ? JSON.stringify(newChip) : newChip;
// TODO add a way for developers to specify which field of the object should be announced here.
var chipContent = angular.isObject(newChip) ? '' : newChip;
this.$mdLiveAnnouncer.announce(chipContent + ' ' + this.addedMessage, 'assertive');

// If the md-on-add attribute is specified, send a chip addition event
Expand Down Expand Up @@ -698,7 +710,8 @@ MdChipsCtrl.prototype.removeChip = function(index, event) {
this.ngModelCtrl.$setDirty();

// Tell screen reader users that the chip was successfully removed.
var chipContent = typeof removed[0] === 'object' ? JSON.stringify(removed[0]) : removed[0];
// TODO add a way for developers to specify which field of the object should be announced here.
var chipContent = angular.isObject(removed[0]) ? '' : removed[0];
this.$mdLiveAnnouncer.announce(chipContent + ' ' + this.removedMessage, 'assertive');

if (removed && removed.length && this.useOnRemove && this.onRemove) {
Expand Down
6 changes: 4 additions & 2 deletions src/components/chips/js/chipsDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@
*
*/

// TODO add a way for developers to specify which field of the object should used in the
// aria-label.
var MD_CHIPS_TEMPLATE = '\
<md-chips-wrap\
id="{{$mdChipsCtrl.wrapperId}}"\
Expand All @@ -229,7 +231,7 @@
aria-setsize="{{$mdChipsCtrl.items.length}}"\
aria-posinset="{{$index+1}}"\
ng-click="!$mdChipsCtrl.readonly && $mdChipsCtrl.focusChip($index)"\
aria-label="{{$chip}}.{{$mdChipsCtrl.isRemovable() ? \' \' + $mdChipsCtrl.deleteHint : \'\'}}" \
aria-label="{{$mdChipsCtrl._isChipObject($chip) ? \'\' : $chip + \'. \'}}{{$mdChipsCtrl.isRemovable() ? \'\' + $mdChipsCtrl.deleteHint : \'\'}}" \
ng-focus="!$mdChipsCtrl.readonly && $mdChipsCtrl.selectChip($index)"\
md-chip-transclude="$mdChipsCtrl.chipContentsTemplate"></div>\
<div ng-if="$mdChipsCtrl.isRemovable()"\
Expand Down Expand Up @@ -263,7 +265,7 @@
ng-click="$mdChipsCtrl.removeChipAndFocusInput($$replacedScope.$index, $event)"\
type="button"\
tabindex="-1"\
aria-label="{{$mdChipsCtrl.deleteButtonLabel}} {{$chip}}">\
aria-label="{{$mdChipsCtrl.deleteButtonLabel}}{{$mdChipsCtrl._isChipObject($chip) ? \'\' : \' \' + $chip}}">\
<md-icon md-svg-src="{{$mdChipsCtrl.mdCloseIcon}}" aria-hidden="true"></md-icon>\
</button>';

Expand Down