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

Commit 5cdceeb

Browse files
crisbetojelbourn
authored andcommitted
fix(sidenav): allow for data bindings in md-component-id (#9255)
Fixes the sidenav not evaluating expressions inside of the `md-component-id` attribute. Fixes #9052.
1 parent bbb9ec5 commit 5cdceeb

File tree

2 files changed

+49
-23
lines changed

2 files changed

+49
-23
lines changed

src/components/sidenav/sidenav.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,7 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming,
252252
},
253253
controller: '$mdSidenavController',
254254
compile: function(element) {
255-
element.addClass('md-closed');
256-
element.attr('tabIndex', '-1');
255+
element.addClass('md-closed').attr('tabIndex', '-1');
257256
return postLink;
258257
}
259258
};
@@ -498,9 +497,8 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming,
498497
* @ngdoc controller
499498
* @name SidenavController
500499
* @module material.components.sidenav
501-
*
502500
*/
503-
function SidenavController($scope, $element, $attrs, $mdComponentRegistry, $q) {
501+
function SidenavController($scope, $attrs, $mdComponentRegistry, $q, $interpolate) {
504502

505503
var self = this;
506504

@@ -522,5 +520,21 @@ function SidenavController($scope, $element, $attrs, $mdComponentRegistry, $q) {
522520
self.toggle = function() { return self.$toggleOpen( !$scope.isOpen ); };
523521
self.$toggleOpen = function(value) { return $q.when($scope.isOpen = value); };
524522

525-
self.destroy = $mdComponentRegistry.register(self, $attrs.mdComponentId);
523+
// Evaluate the component id.
524+
var rawId = $attrs.mdComponentId;
525+
var hasDataBinding = rawId && rawId.indexOf($interpolate.startSymbol()) > -1;
526+
var componentId = hasDataBinding ? $interpolate(rawId)($scope.$parent) : rawId;
527+
528+
// Register the component.
529+
self.destroy = $mdComponentRegistry.register(self, componentId);
530+
531+
// Watch and update the component, if the id has changed.
532+
if (hasDataBinding) {
533+
$attrs.$observe('mdComponentId', function(id) {
534+
if (id && id !== self.$$mdHandle) {
535+
self.destroy(); // `destroy` only deregisters the old component id so we can add the new one.
536+
self.destroy = $mdComponentRegistry.register(self, id);
537+
}
538+
});
539+
}
526540
}

src/components/sidenav/sidenav.spec.js

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
describe('mdSidenav', function() {
22
beforeEach(module('material.components.sidenav'));
33

4-
function setup(attrs) {
4+
function setup(attrs, skipInitialDigest) {
55
var el;
66
inject(function($compile, $rootScope) {
77
var parent = angular.element('<div>');
88
el = angular.element('<md-sidenav ' + (attrs || '') + '>');
99
parent.append(el);
1010
$compile(parent)($rootScope);
11-
$rootScope.$apply();
11+
!skipInitialDigest && $rootScope.$apply();
1212
});
1313
return el;
1414
}
@@ -225,13 +225,13 @@ describe('mdSidenav', function() {
225225

226226
describe('controller', function() {
227227
it('should create controller', function() {
228-
var el = setup('');
228+
var el = setup();
229229
var controller = el.controller('mdSidenav');
230230
expect(controller).not.toBe(undefined);
231231
});
232232

233233
it('should open and close and toggle', inject(function($timeout) {
234-
var el = setup('');
234+
var el = setup();
235235
var scope = el.isolateScope();
236236
var controller = el.controller('mdSidenav');
237237

@@ -270,7 +270,7 @@ describe('mdSidenav', function() {
270270
}));
271271

272272
it('should open(), close(), and toggle() with promises', function() {
273-
var el = setup('');
273+
var el = setup();
274274
var scope = el.isolateScope();
275275
var controller = el.controller('mdSidenav');
276276

@@ -314,7 +314,7 @@ describe('mdSidenav', function() {
314314
});
315315

316316
it('should open() to work multiple times before close()', function() {
317-
var el = setup('');
317+
var el = setup();
318318
var controller = el.controller('mdSidenav');
319319

320320
var openDone = 0, closeDone = 0;
@@ -408,23 +408,35 @@ describe('mdSidenav', function() {
408408
});
409409

410410
describe('$mdSidenav lookups', function() {
411-
var $rootScope, $timeout;
411+
var $rootScope, $timeout, $mdSidenav;
412412

413-
beforeEach(inject(function(_$rootScope_, _$timeout_) {
413+
beforeEach(inject(function(_$rootScope_, _$timeout_, _$mdSidenav_) {
414414
$rootScope = _$rootScope_;
415415
$timeout = _$timeout_;
416+
$mdSidenav = _$mdSidenav_;
416417
}));
417418

418-
it('should find an instantiation using `$mdSidenav(id)`', inject(function($mdSidenav) {
419+
it('should find an instantiation using `$mdSidenav(id)`', function() {
419420
var el = setup('md-component-id="left"');
420421
$timeout.flush();
421422

422423
// Lookup instance still available in the component registry
423424
var instance = $mdSidenav('left');
424425
expect(instance).toBeTruthy();
425-
}));
426+
});
426427

427-
it('should find a deferred instantiation using `$mdSidenav(id, true)`', inject(function($mdSidenav) {
428+
it('should support data bindings', function() {
429+
// It should work on init.
430+
$rootScope.leftComponentId = 'left';
431+
setup('md-component-id="{{ leftComponentId }}"', true);
432+
expect($mdSidenav($rootScope.leftComponentId, false)).toBeTruthy();
433+
434+
// It should also work if the data binding has changed.
435+
$rootScope.$apply('leftComponentId = "otherLeft"');
436+
expect($mdSidenav($rootScope.leftComponentId, false)).toBeTruthy();
437+
});
438+
439+
it('should find a deferred instantiation using `$mdSidenav(id, true)`', function() {
428440
var instance;
429441

430442
// Lookup deferred (not existing) instance
@@ -443,9 +455,9 @@ describe('mdSidenav', function() {
443455
// Lookup instance still available in the component registry
444456
instance = $mdSidenav('left', true);
445457
expect(instance).toBeTruthy();
446-
}));
458+
});
447459

448-
it('should find a deferred instantiation using `$mdSidenav().waitFor(id)` ', inject(function($mdSidenav) {
460+
it('should find a deferred instantiation using `$mdSidenav().waitFor(id)` ', function() {
449461
var instance;
450462

451463
// Lookup deferred (not existing) instance
@@ -466,9 +478,9 @@ describe('mdSidenav', function() {
466478
instance = $mdSidenav('left');
467479

468480
expect(instance).toBeTruthy();
469-
}));
481+
});
470482

471-
it('should not find a lazy instantiation without waiting `$mdSidenav(id)`', inject(function($mdSidenav) {
483+
it('should not find a lazy instantiation without waiting `$mdSidenav(id)`', function() {
472484
var instance = $mdSidenav('left');
473485
expect(instance.isOpen).toBeDefined(); // returns legacy API with noops
474486

@@ -482,9 +494,9 @@ describe('mdSidenav', function() {
482494
instance = $mdSidenav('left'); // returns instance
483495
expect(instance).toBeDefined();
484496
expect(instance.isOpen()).toBeFalsy();
485-
}));
497+
});
486498

487-
it('should not find a lazy instantiation without waiting `$mdSidenav().find(id)`', inject(function($mdSidenav) {
499+
it('should not find a lazy instantiation without waiting `$mdSidenav().find(id)`', function() {
488500
var instance = $mdSidenav().find('left');
489501
expect(instance).toBeUndefined();
490502

@@ -495,7 +507,7 @@ describe('mdSidenav', function() {
495507
instance = $mdSidenav().find('left');
496508
expect(instance).toBeDefined();
497509
expect(instance.isOpen()).toBeFalsy();
498-
}));
510+
});
499511

500512
describe('onClose', function () {
501513
it('should call callback on escape', inject(function($mdSidenav, $rootScope, $material, $mdConstant, $timeout) {

0 commit comments

Comments
 (0)