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

Commit 546bd84

Browse files
committed
fix(select): revert removal of support for ng-selected on md-options
- add unit test to ensure `ng-selected` support continues to work - add docs for `ng-selected` on `md-option` Fixes #11914
1 parent fd4e737 commit 546bd84

File tree

2 files changed

+45
-6
lines changed

2 files changed

+45
-6
lines changed

src/components/select/select.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,12 @@ function SelectMenuDirective($parse, $mdUtil, $mdConstant, $mdTheming) {
11701170
* @param {string=} value Attribute to set the value of the option.
11711171
* @param {expression=} ng-repeat <a ng-href="https://docs.angularjs.org/api/ng/directive/ngRepeat">
11721172
* AngularJS directive</a> that instantiates a template once per item from a collection.
1173+
* @param {expression=} ng-selected <a ng-href="https://docs.angularjs.org/api/ng/directive/ngSelected">
1174+
* AngularJS directive</a> that adds the `selected` attribute to the option when the expression
1175+
* evaluates as truthy.
1176+
*
1177+
* **Note:** Unlike native `option` elements used with AngularJS, `md-option` elements
1178+
* watch their `selected` attributes for changes and trigger model value changes on `md-select`.
11731179
* @param {boolean=} md-option-empty If the attribute exists, mark the option as "empty" allowing
11741180
* the option to clear the select and put it back in it's default state. You may supply this
11751181
* attribute on any option you wish, however, it is automatically applied to an option whose `value`
@@ -1258,14 +1264,30 @@ function OptionDirective($mdButtonInkRipple, $mdUtil, $mdTheming) {
12581264
}
12591265
});
12601266

1267+
scope.$$postDigest(function() {
1268+
attrs.$observe('selected', function(selected) {
1269+
if (!angular.isDefined(selected)) return;
1270+
if (typeof selected == 'string') selected = true;
1271+
if (selected) {
1272+
if (!selectMenuCtrl.isMultiple) {
1273+
selectMenuCtrl.deselect(Object.keys(selectMenuCtrl.selected)[0]);
1274+
}
1275+
selectMenuCtrl.select(optionCtrl.hashKey, optionCtrl.value);
1276+
} else {
1277+
selectMenuCtrl.deselect(optionCtrl.hashKey);
1278+
}
1279+
selectMenuCtrl.refreshViewValue();
1280+
});
1281+
});
1282+
12611283
$mdButtonInkRipple.attach(scope, element);
12621284
configureAria();
12631285

12641286
/**
12651287
* @param {*} newValue the option's new value
12661288
* @param {*=} oldValue the option's previous value
12671289
* @param {boolean=} prevAttempt true if this had to be attempted again due to an undefined
1268-
* hashGetter on the selectCtrl, undefined otherwise.
1290+
* hashGetter on the selectMenuCtrl, undefined otherwise.
12691291
*/
12701292
function setOptionValue(newValue, oldValue, prevAttempt) {
12711293
if (!selectMenuCtrl.hashGetter) {

src/components/select/select.spec.js

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,15 @@ describe('<md-select>', function() {
738738
expect(selectedOptions(el).length).toBe(0);
739739
});
740740

741+
it('supports ng-selected on md-options', function() {
742+
var el = setupSelect('ng-model="$root.model"', ['a','b','c'], false, $rootScope, null,
743+
'$index === 2');
744+
745+
expect(selectedOptions(el).length).toBe(1);
746+
expect(el.find('md-option').eq(2).attr('selected')).toBe('selected');
747+
expect($rootScope.model).toBe('c');
748+
});
749+
741750
it('supports circular references', function() {
742751
var opts = [{ id: 1 }, { id: 2 }];
743752
opts[0].refs = opts[1];
@@ -1688,13 +1697,13 @@ describe('<md-select>', function() {
16881697
});
16891698
}
16901699

1691-
function setupSelect(attrs, options, skipLabel, scope, optCompileOpts) {
1700+
function setupSelect(attrs, options, skipLabel, scope, optCompileOpts, ngSelectedExpression) {
16921701
var el;
16931702
var template = '' +
16941703
'<md-input-container>' +
16951704
(skipLabel ? '' : '<label>Label</label>') +
16961705
'<md-select ' + (attrs || '') + '>' +
1697-
optTemplate(options, optCompileOpts) +
1706+
optTemplate(options, optCompileOpts, ngSelectedExpression) +
16981707
'</md-select>' +
16991708
'</md-input-container>';
17001709

@@ -1713,13 +1722,21 @@ describe('<md-select>', function() {
17131722
return toReturn;
17141723
}
17151724

1716-
function optTemplate(options, compileOpts) {
1725+
/**
1726+
* @param {any[]=} options Array of option values to create md-options from
1727+
* @param {object=} compileOpts
1728+
* @param {object=} ngSelectedExpression If defined, sets the expression used by ng-selected.
1729+
* @return {string} template containing the generated md-options
1730+
*/
1731+
function optTemplate(options, compileOpts, ngSelectedExpression) {
17171732
var optionsTpl = '';
1733+
var ngSelectedTemplate = ngSelectedExpression ? ' ng-selected="' + ngSelectedExpression + '"' : '';
17181734

17191735
if (angular.isArray(options)) {
17201736
$rootScope.$$values = options;
17211737
var renderValueAs = compileOpts ? compileOpts.renderValueAs || 'value' : 'value';
1722-
optionsTpl = '<md-option ng-repeat="value in $$values" ng-value="value"><div class="md-text">{{' + renderValueAs + '}}</div></md-option>';
1738+
optionsTpl = '<md-option ng-repeat="value in $$values" ng-value="value"' + ngSelectedTemplate + '>' +
1739+
'<div class="md-text">{{' + renderValueAs + '}}</div></md-option>';
17231740
} else if (angular.isString(options)) {
17241741
optionsTpl = options;
17251742
}
@@ -1739,7 +1756,7 @@ describe('<md-select>', function() {
17391756
}
17401757

17411758
function openSelect(el) {
1742-
if (el[0].nodeName != 'MD-SELECT') {
1759+
if (el[0].nodeName !== 'MD-SELECT') {
17431760
el = el.find('md-select');
17441761
}
17451762
try {

0 commit comments

Comments
 (0)