From d553919130cf85314c10a19b27a9b5c9665cdac9 Mon Sep 17 00:00:00 2001 From: Topher Fangio Date: Wed, 12 Oct 2016 10:53:03 -0500 Subject: [PATCH] fix(select): Fix duplicates in label. (#9695) Occasionally, `ng-repeat` appears to modify the DOM in such a way that it allows duplicates of selected items. When this happens, the `md-select` has issues displaying the proper label. Add a quick filter to ensure there are no duplicate selections in our labels. NOTE: I was unable to reproduce this in a spec; it appears to be related to the scope digets and never happens in the spec. I did update one of the demos to do some manual testing and ensure this fix works as expected, but it didn't have any real use inside of the demo so I removed it before submission. Fixes #9442. --- src/components/select/select.js | 8 +++++--- src/core/util/util.js | 19 +++++++++++++++++++ src/core/util/util.spec.js | 14 ++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/components/select/select.js b/src/components/select/select.js index 326b179ec43..ad766dd2754 100755 --- a/src/components/select/select.js +++ b/src/components/select/select.js @@ -174,7 +174,7 @@ angular.module('material.components.select', [ * * */ -function SelectDirective($mdSelect, $mdUtil, $mdConstant, $mdTheming, $mdAria, $compile, $parse) { +function SelectDirective($mdSelect, $mdUtil, $mdConstant, $mdTheming, $mdAria, $parse) { var keyCodes = $mdConstant.KEY_CODE; var NAVIGATION_KEYS = [keyCodes.SPACE, keyCodes.ENTER, keyCodes.UP_ARROW, keyCodes.DOWN_ARROW]; @@ -408,7 +408,7 @@ function SelectDirective($mdSelect, $mdUtil, $mdConstant, $mdTheming, $mdAria, $ } scope.$watch(function() { - return selectMenuCtrl.selectedLabels(); + return selectMenuCtrl.selectedLabels(); }, syncLabelText); function syncLabelText() { @@ -792,7 +792,9 @@ function SelectMenuDirective($parse, $mdUtil, $mdConstant, $mdTheming) { } else if (mode == 'aria') { mapFn = function(el) { return el.hasAttribute('aria-label') ? el.getAttribute('aria-label') : el.textContent; }; } - return selectedOptionEls.map(mapFn).join(', '); + + // Ensure there are no duplicates; see https://github.com/angular/material/issues/9442 + return $mdUtil.uniq(selectedOptionEls.map(mapFn)).join(', '); } else { return ''; } diff --git a/src/core/util/util.js b/src/core/util/util.js index 8b30ae4f333..6906d888003 100644 --- a/src/core/util/util.js +++ b/src/core/util/util.js @@ -833,6 +833,25 @@ function UtilFactory($document, $timeout, $compile, $rootScope, $$mdAnimate, $in return start + change * (-2 * tc + 3 * ts); } + }, + + /** + * Provides an easy mechanism for removing duplicates from an array. + * + * var myArray = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]; + * + * $mdUtil.uniq(myArray) => [1, 2, 3, 4] + * + * @param {array} array The array whose unique values should be returned. + * + * @returns {array} A copy of the array containing only unique values. + */ + uniq: function(array) { + if (!array) { return; } + + return array.filter(function(value, index, self) { + return self.indexOf(value) === index; + }); } }; diff --git a/src/core/util/util.spec.js b/src/core/util/util.spec.js index d5657f471ec..669f37b4742 100644 --- a/src/core/util/util.spec.js +++ b/src/core/util/util.spec.js @@ -717,4 +717,18 @@ describe('util', function() { parent.remove(); }); }); + + describe('uniq', function() { + var $mdUtil; + + beforeEach(inject(function(_$mdUtil_) { + $mdUtil = _$mdUtil_; + })); + + it('returns a copy of the requested array with only unique values', function() { + var myArray = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]; + + expect($mdUtil.uniq(myArray)).toEqual([1, 2, 3, 4]); + }); + }); });