diff --git a/src/components/sidenav/sidenav.js b/src/components/sidenav/sidenav.js index cbd2a4ccbb3..4005b782624 100644 --- a/src/components/sidenav/sidenav.js +++ b/src/components/sidenav/sidenav.js @@ -249,8 +249,7 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate, }, controller: '$mdSidenavController', compile: function(element) { - element.addClass('md-closed'); - element.attr('tabIndex', '-1'); + element.addClass('md-closed').attr('tabIndex', '-1'); return postLink; } }; @@ -481,9 +480,8 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate, * @ngdoc controller * @name SidenavController * @module material.components.sidenav - * */ -function SidenavController($scope, $element, $attrs, $mdComponentRegistry, $q) { +function SidenavController($scope, $attrs, $mdComponentRegistry, $q, $interpolate) { var self = this; @@ -505,5 +503,21 @@ function SidenavController($scope, $element, $attrs, $mdComponentRegistry, $q) { self.toggle = function() { return self.$toggleOpen( !$scope.isOpen ); }; self.$toggleOpen = function(value) { return $q.when($scope.isOpen = value); }; - self.destroy = $mdComponentRegistry.register(self, $attrs.mdComponentId); + // Evaluate the component id. + var rawId = $attrs.mdComponentId; + var hasDataBinding = rawId && rawId.indexOf($interpolate.startSymbol()) > -1; + var componentId = hasDataBinding ? $interpolate(rawId)($scope.$parent) : rawId; + + // Register the component. + self.destroy = $mdComponentRegistry.register(self, componentId); + + // Watch and update the component, if the id has changed. + if (hasDataBinding) { + $attrs.$observe('mdComponentId', function(id) { + if (id && id !== self.$$mdHandle) { + self.destroy(); // `destroy` only deregisters the old component id so we can add the new one. + self.destroy = $mdComponentRegistry.register(self, id); + } + }); + } } diff --git a/src/components/sidenav/sidenav.spec.js b/src/components/sidenav/sidenav.spec.js index 3449a94e61d..3ea49b15717 100644 --- a/src/components/sidenav/sidenav.spec.js +++ b/src/components/sidenav/sidenav.spec.js @@ -1,14 +1,14 @@ describe('mdSidenav', function() { beforeEach(module('material.components.sidenav')); - function setup(attrs) { + function setup(attrs, skipInitialDigest) { var el; inject(function($compile, $rootScope) { var parent = angular.element('
'); el = angular.element(''); parent.append(el); $compile(parent)($rootScope); - $rootScope.$apply(); + !skipInitialDigest && $rootScope.$apply(); }); return el; } @@ -168,13 +168,13 @@ describe('mdSidenav', function() { describe('controller', function() { it('should create controller', function() { - var el = setup(''); + var el = setup(); var controller = el.controller('mdSidenav'); expect(controller).not.toBe(undefined); }); it('should open and close and toggle', inject(function($timeout) { - var el = setup(''); + var el = setup(); var scope = el.isolateScope(); var controller = el.controller('mdSidenav'); @@ -213,7 +213,7 @@ describe('mdSidenav', function() { })); it('should open(), close(), and toggle() with promises', function() { - var el = setup(''); + var el = setup(); var scope = el.isolateScope(); var controller = el.controller('mdSidenav'); @@ -257,7 +257,7 @@ describe('mdSidenav', function() { }); it('should open() to work multiple times before close()', function() { - var el = setup(''); + var el = setup(); var controller = el.controller('mdSidenav'); var openDone = 0, closeDone = 0; @@ -351,23 +351,35 @@ describe('mdSidenav', function() { }); describe('$mdSidenav lookups', function() { - var $rootScope, $timeout; + var $rootScope, $timeout, $mdSidenav; - beforeEach(inject(function(_$rootScope_, _$timeout_) { + beforeEach(inject(function(_$rootScope_, _$timeout_, _$mdSidenav_) { $rootScope = _$rootScope_; $timeout = _$timeout_; + $mdSidenav = _$mdSidenav_; })); - it('should find an instantiation using `$mdSidenav(id)`', inject(function($mdSidenav) { + it('should find an instantiation using `$mdSidenav(id)`', function() { var el = setup('md-component-id="left"'); $timeout.flush(); // Lookup instance still available in the component registry var instance = $mdSidenav('left'); expect(instance).toBeTruthy(); - })); + }); - it('should find a deferred instantiation using `$mdSidenav(id, true)`', inject(function($mdSidenav) { + it('should support data bindings', function() { + // It should work on init. + $rootScope.leftComponentId = 'left'; + setup('md-component-id="{{ leftComponentId }}"', true); + expect($mdSidenav($rootScope.leftComponentId, false)).toBeTruthy(); + + // It should also work if the data binding has changed. + $rootScope.$apply('leftComponentId = "otherLeft"'); + expect($mdSidenav($rootScope.leftComponentId, false)).toBeTruthy(); + }); + + it('should find a deferred instantiation using `$mdSidenav(id, true)`', function() { var instance; // Lookup deferred (not existing) instance @@ -386,9 +398,9 @@ describe('mdSidenav', function() { // Lookup instance still available in the component registry instance = $mdSidenav('left', true); expect(instance).toBeTruthy(); - })); + }); - it('should find a deferred instantiation using `$mdSidenav().waitFor(id)` ', inject(function($mdSidenav) { + it('should find a deferred instantiation using `$mdSidenav().waitFor(id)` ', function() { var instance; // Lookup deferred (not existing) instance @@ -409,9 +421,9 @@ describe('mdSidenav', function() { instance = $mdSidenav('left'); expect(instance).toBeTruthy(); - })); + }); - it('should not find a lazy instantiation without waiting `$mdSidenav(id)`', inject(function($mdSidenav) { + it('should not find a lazy instantiation without waiting `$mdSidenav(id)`', function() { var instance = $mdSidenav('left'); expect(instance.isOpen).toBeDefined(); // returns legacy API with noops @@ -425,9 +437,9 @@ describe('mdSidenav', function() { instance = $mdSidenav('left'); // returns instance expect(instance).toBeDefined(); expect(instance.isOpen()).toBeFalsy(); - })); + }); - it('should not find a lazy instantiation without waiting `$mdSidenav().find(id)`', inject(function($mdSidenav) { + it('should not find a lazy instantiation without waiting `$mdSidenav().find(id)`', function() { var instance = $mdSidenav().find('left'); expect(instance).toBeUndefined(); @@ -438,7 +450,7 @@ describe('mdSidenav', function() { instance = $mdSidenav().find('left'); expect(instance).toBeDefined(); expect(instance.isOpen()).toBeFalsy(); - })); + }); describe('onClose', function () { it('should call callback on escape', inject(function($mdSidenav, $rootScope, $material, $mdConstant, $timeout) {