From e07c52da12789c4634878eec612c7137feb17935 Mon Sep 17 00:00:00 2001 From: Ryan Schmukler Date: Fri, 20 Nov 2015 15:21:09 -0500 Subject: [PATCH] feat(select): add support for raw HTML in options closes #2242, closes #5847 --- src/components/select/select.js | 12 +---- src/components/select/select.spec.js | 66 ++++++++++++++++++---------- 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/src/components/select/select.js b/src/components/select/select.js index 662d1b047a1..a1fe8c960d3 100755 --- a/src/components/select/select.js +++ b/src/components/select/select.js @@ -5,14 +5,6 @@ /*************************************************** - ### TODO ### - **DOCUMENTATION AND DEMOS** - - - [ ] ng-model with child mdOptions (basic) - - [ ] ng-model="foo" ng-model-options="{ trackBy: '$value.id' }" for objects - - [ ] mdOption with value - - [ ] Usage with input inside - ### TODO - POST RC1 ### - [ ] Abstract placement logic in $mdSelect service to $mdMenu service @@ -257,7 +249,7 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $compile, $par var tmpPlaceholder = attr.placeholder || (containerCtrl && containerCtrl.label ? containerCtrl.label.text() : ''); text = text || tmpPlaceholder || ''; var target = valueEl.children().eq(0); - target.text(text); + target.html(text); }; mdSelectCtrl.setIsPlaceholder = function(isPlaceholder) { @@ -638,7 +630,7 @@ function SelectMenuDirective($parse, $mdUtil, $mdTheming) { var selectedOptionEls = $mdUtil.nodesToArray($element[0].querySelectorAll('md-option[selected]')); if (selectedOptionEls.length) { return selectedOptionEls.map(function(el) { - return el.textContent; + return el.innerHTML; }).join(', '); } else { return ''; diff --git a/src/components/select/select.spec.js b/src/components/select/select.spec.js index fbc73ad7b30..e38dbe16364 100755 --- a/src/components/select/select.spec.js +++ b/src/components/select/select.spec.js @@ -17,15 +17,15 @@ describe('', function() { backdrops.remove(); })); - it('should preserve tabindex', inject(function($document) { + it('should preserve tabindex', function() { var select = setupSelect('tabindex="2", ng-model="val"').find('md-select'); expect(select.attr('tabindex')).toBe('2'); - })); + }); - it('supports non-disabled state', inject(function($document) { + it('supports non-disabled state', function() { var select = setupSelect('ng-model="val"').find('md-select'); expect(select.attr('aria-disabled')).toBe('false'); - })); + }); it('supports disabled state', inject(function($document) { var select = setupSelect('disabled="disabled", ng-model="val"').find('md-select'); @@ -34,7 +34,7 @@ describe('', function() { expect(select.attr('aria-disabled')).toBe('true'); })); - it('supports passing classes to the container', inject(function($document, $timeout) { + it('supports passing classes to the container', inject(function($document) { var select = setupSelect('ng-model="val", md-container-class="test"').find('md-select'); openSelect(select); @@ -142,7 +142,7 @@ describe('', function() { openSelect(select); - var opt = $document.find('md-option')[0].click(); + $document.find('md-option')[0].click(); waitForSelectClose(); @@ -158,17 +158,17 @@ describe('', function() { expect(el).not.toHaveClass('md-input-has-value'); })); - it('should match label to given input id', inject(function($rootScope) { + it('should match label to given input id', function() { var el = setupSelect('ng-model="$root.value", id="foo"'); expect(el.find('label').attr('for')).toBe('foo'); expect(el.find('md-select').attr('id')).toBe('foo'); - })); + }); - it('should match label to automatic input id', inject(function($rootScope) { + it('should match label to automatic input id', function() { var el = setupSelect('ng-model="$root.value"'); expect(el.find('md-select').attr('id')).toBeTruthy(); expect(el.find('label').attr('for')).toBe(el.find('md-select').attr('id')); - })); + }); }); describe('label behavior', function() { @@ -212,6 +212,29 @@ describe('', function() { expect(label.text()).toBe('One, Three'); expect(label.hasClass('md-select-placeholder')).toBe(false); })); + + it('supports raw html', inject(function($rootScope, $compile, $sce) { + $rootScope.val = 0; + $rootScope.opts = [ + { id: 0, label: '

Hello World

' }, + { id: 1, label: 'Hello World' } + ]; + angular.forEach($rootScope.opts, function(opt) { + opt.label = $sce.trustAs('html', opt.label); + }); + var select = $compile('' + + '' + + '' + + '' + + '' + + '')($rootScope).find('md-select'); + var label = select.find('md-select-value').children().eq(0); + $rootScope.$digest(); + + + expect(label.text()).toBe('Hello World'); + expect(label.html()).toBe('

Hello World

'); + })); }); it('auto-infers a value when none specified', inject(function($rootScope) { @@ -221,7 +244,7 @@ describe('', function() { expect(selectedOptions(el).length).toBe(1); })); - it('errors for duplicate md-options, non-dynamic value', inject(function($rootScope) { + it('errors for duplicate md-options, non-dynamic value', inject(function() { expect(function() { setup('ng-model="$root.model"', 'Hello' + 'Goodbye'); @@ -582,7 +605,7 @@ describe('', function() { it('does not let an empty array satisfy required', inject(function($rootScope, $compile) { $rootScope.model = []; $rootScope.opts = [1, 2, 3, 4]; - var form = $compile('
' + + $compile('' + '' + '' + '
')($rootScope); @@ -689,25 +712,24 @@ describe('', function() { expect(select.attr('aria-label')).toBe('Pick'); })); - it('preserves existing aria-label', inject(function($rootScope) { + it('preserves existing aria-label', function() { var select = setupSelect('ng-model="someVal", aria-label="Hello world", placeholder="Pick"').find('md-select'); expect(select.attr('aria-label')).toBe('Hello world'); - })); + }); it('should expect an aria-label if none is present', inject(function($compile, $rootScope, $log) { spyOn($log, 'warn'); - var select = setupSelect('ng-model="someVal"', null, true).find('md-select'); + setupSelect('ng-model="someVal"', null, true).find('md-select'); $rootScope.$apply(); expect($log.warn).toHaveBeenCalled(); $log.warn.calls.reset(); - select = setupSelect('ng-model="someVal", aria-label="Hello world"').find('md-select'); + setupSelect('ng-model="someVal", aria-label="Hello world"').find('md-select'); $rootScope.$apply(); expect($log.warn).not.toHaveBeenCalled(); })); - it('sets up the aria-expanded attribute', inject(function($document, $timeout) { - disableAnimations(); + it('sets up the aria-expanded attribute', inject(function($document) { expect(el.attr('aria-expanded')).toBe('false'); openSelect(el); @@ -725,7 +747,7 @@ describe('', function() { expect(el.attr('aria-multiselectable')).toBe('true'); })); - it('sets up the aria-selected attribute', inject(function($rootScope) { + it('sets up the aria-selected attribute', function() { var el = setup('ng-model="$root.model"', [1,2,3]); var options = el.find('md-option'); expect(options.eq(2).attr('aria-selected')).toBe('false'); @@ -734,7 +756,7 @@ describe('', function() { target: el.find('md-option')[2] }); expect(options.eq(2).attr('aria-selected')).toBe('true'); - })); + }); }); describe('keyboard controls', function() { @@ -786,9 +808,7 @@ describe('', function() { }); describe('md-select-menu', function() { - it('can be closed with escape', inject(function($document, $rootScope, $animate) { - disableAnimations(); - + it('can be closed with escape', inject(function($document) { var el = setupSelect('ng-model="someVal"', [1, 2, 3]).find('md-select'); openSelect(el); var selectMenu = angular.element($document.find('md-select-menu'));