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

Commit b89beee

Browse files
Splaktarmmalerba
authored andcommitted
fix(chips): don't throw when chip models are recursive, complex objects (#11535)
- improve basic demo and md-chip-remove directive docs - no longer parse JSON object in order to try to provide some useful identifier in messages
1 parent f90715c commit b89beee

File tree

4 files changed

+44
-14
lines changed

4 files changed

+44
-14
lines changed

src/components/chips/demoBasicUsage/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ <h2 class="md-title">Display an ordered set of objects as chips (with custom tem
6969
<em>({{$chip.type}})</em>
7070
</span>
7171
</md-chip-template>
72-
<button md-chip-remove class="md-primary vegetablechip">
72+
<button md-chip-remove class="md-primary vegetablechip" aria-label="Remove {{$chip.name}}">
7373
<md-icon md-svg-icon="md-close"></md-icon>
7474
</button>
7575
</md-chips>

src/components/chips/js/chipRemoveDirective.js

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,31 @@ angular
99
* @module material.components.chips
1010
*
1111
* @description
12-
* Designates an element to be used as the delete button for a chip. <br/>
13-
* This element is passed as a child of the `md-chips` element.
12+
* Indicates that the associated element should be used as the delete button template for all chips.
13+
* The associated element must be a child of `md-chips`.
1414
*
15-
* The designated button will be just appended to the chip and removes the given chip on click.<br/>
16-
* By default the button is not being styled by the `md-chips` component.
15+
* The provided button template will be appended to each chip and will remove the associated chip
16+
* on click.
17+
*
18+
* The button is not styled or themed based on the theme set on the `md-chips` component. A theme
19+
* class and custom icon can be specified in your template.
20+
*
21+
* You can also specify the `type` of the button in your template.
1722
*
1823
* @usage
24+
* ### With Standard Chips
25+
* <hljs lang="html">
26+
* <md-chips ...>
27+
* <button md-chip-remove class="md-primary" type="button" aria-label="Remove {{$chip}}">
28+
* <md-icon md-svg-icon="md-close"></md-icon>
29+
* </button>
30+
* </md-chips>
31+
* </hljs>
32+
*
33+
* ### With Object Chips
1934
* <hljs lang="html">
20-
* <md-chips>
21-
* <button md-chip-remove="">
35+
* <md-chips ...>
36+
* <button md-chip-remove class="md-primary" type="button" aria-label="Remove {{$chip.name}}">
2237
* <md-icon md-svg-icon="md-close"></md-icon>
2338
* </button>
2439
* </md-chips>
@@ -51,7 +66,7 @@ function MdChipRemove ($timeout) {
5166
// Child elements aren't available until after a $timeout tick as they are hidden by an
5267
// `ng-if`. see http://goo.gl/zIWfuw
5368
$timeout(function() {
54-
element.attr({ tabindex: -1, 'aria-hidden': true });
69+
element.attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
5570
element.find('button').attr('tabindex', '-1');
5671
});
5772
}

src/components/chips/js/chipsController.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,18 @@ MdChipsCtrl.prototype.isEditingChip = function() {
413413
return !!this.$element[0].querySelector('._md-chip-editing');
414414
};
415415

416+
/**
417+
* @param {string|Object} chip contents of a single chip
418+
* @returns {boolean} true if the chip is an Object, false otherwise.
419+
* @private
420+
*/
421+
MdChipsCtrl.prototype._isChipObject = function(chip) {
422+
return angular.isObject(chip);
423+
};
416424

425+
/**
426+
* @returns {boolean} true if chips can be removed, false otherwise.
427+
*/
417428
MdChipsCtrl.prototype.isRemovable = function() {
418429
// Return false if we have static chips
419430
if (!this.ngModelCtrl) {
@@ -543,8 +554,8 @@ MdChipsCtrl.prototype.appendChip = function(newChip) {
543554
}
544555

545556
// If items contains an identical object to newChip, do not append
546-
if (angular.isObject(newChip)){
547-
var identical = this.items.some(function(item){
557+
if (angular.isObject(newChip)) {
558+
var identical = this.items.some(function(item) {
548559
return angular.equals(newChip, item);
549560
});
550561
if (identical) return;
@@ -560,7 +571,8 @@ MdChipsCtrl.prototype.appendChip = function(newChip) {
560571
this.updateNgModel();
561572

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

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

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

704717
if (removed && removed.length && this.useOnRemove && this.onRemove) {

src/components/chips/js/chipsDirective.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@
209209
*
210210
*/
211211

212+
// TODO add a way for developers to specify which field of the object should used in the
213+
// aria-label.
212214
var MD_CHIPS_TEMPLATE = '\
213215
<md-chips-wrap\
214216
id="{{$mdChipsCtrl.wrapperId}}"\
@@ -229,7 +231,7 @@
229231
aria-setsize="{{$mdChipsCtrl.items.length}}"\
230232
aria-posinset="{{$index+1}}"\
231233
ng-click="!$mdChipsCtrl.readonly && $mdChipsCtrl.focusChip($index)"\
232-
aria-label="{{$chip}}.{{$mdChipsCtrl.isRemovable() ? \' \' + $mdChipsCtrl.deleteHint : \'\'}}" \
234+
aria-label="{{$mdChipsCtrl._isChipObject($chip) ? \'\' : $chip + \'. \'}}{{$mdChipsCtrl.isRemovable() ? \'\' + $mdChipsCtrl.deleteHint : \'\'}}" \
233235
ng-focus="!$mdChipsCtrl.readonly && $mdChipsCtrl.selectChip($index)"\
234236
md-chip-transclude="$mdChipsCtrl.chipContentsTemplate"></div>\
235237
<div ng-if="$mdChipsCtrl.isRemovable()"\
@@ -263,7 +265,7 @@
263265
ng-click="$mdChipsCtrl.removeChipAndFocusInput($$replacedScope.$index, $event)"\
264266
type="button"\
265267
tabindex="-1"\
266-
aria-label="{{$mdChipsCtrl.deleteButtonLabel}} {{$chip}}">\
268+
aria-label="{{$mdChipsCtrl.deleteButtonLabel}}{{$mdChipsCtrl._isChipObject($chip) ? \'\' : \' \' + $chip}}">\
267269
<md-icon md-svg-src="{{$mdChipsCtrl.mdCloseIcon}}" aria-hidden="true"></md-icon>\
268270
</button>';
269271

0 commit comments

Comments
 (0)