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

Commit 076a97d

Browse files
feat(sidenav): add promise-based lookup .then(callbackFn) for deferred instances
Closes #1311.
1 parent f3cd5b9 commit 076a97d

2 files changed

Lines changed: 94 additions & 13 deletions

File tree

src/components/sidenav/sidenav.js

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,44 +29,71 @@ angular.module('material.components.sidenav', [
2929
*
3030
* @usage
3131
* <hljs lang="js">
32-
* // Toggle the given sidenav
33-
* $mdSidenav(componentId).toggle();
32+
* // Async lookup for sidenav instance; will resolve when the instance is available
33+
* $mdSidenav(componentId).then(function(instance) {
34+
* $log.debug( componentId + "is now ready" );
35+
* });
36+
* </hljs>
37+
* <hljs lang="js">
38+
* // Async toggle the given sidenav;
39+
* // when instance is known ready and lazy lookup is not needed.
40+
* $mdSidenav(componentId)
41+
* .toggle()
42+
* .then(function(){
43+
* $log.debug('toggled');
44+
* });
3445
* </hljs>
3546
* <hljs lang="js">
36-
* // Open the given sidenav
37-
* $mdSidenav(componentId).open();
47+
* // Async open the given sidenav
48+
* $mdSidenav(componentId)
49+
* .open();
50+
* .then(function(){
51+
* $log.debug('opened');
52+
* });
3853
* </hljs>
3954
* <hljs lang="js">
40-
* // Close the given sidenav
41-
* $mdSidenav(componentId).close();
55+
* // Async close the given sidenav
56+
* $mdSidenav(componentId)
57+
* .close();
58+
* .then(function(){
59+
* $log.debug('closed');
60+
* });
4261
* </hljs>
4362
* <hljs lang="js">
44-
* // Exposes whether given sidenav is set to be open
63+
* // Sync check to see if the specified sidenav is set to be open
4564
* $mdSidenav(componentId).isOpen();
4665
* </hljs>
4766
* <hljs lang="js">
48-
* // Exposes whether given sidenav is locked open
49-
* // If this is true, the sidenav will be open regardless of isOpen()
67+
* // Sync check to whether given sidenav is locked open
68+
* // If this is true, the sidenav will be open regardless of close()
5069
* $mdSidenav(componentId).isLockedOpen();
5170
* </hljs>
5271
*/
5372
function SidenavService($mdComponentRegistry, $q) {
5473
return function(handle) {
55-
var errorMsg = "SideNav '" + handle + "' is not available!";
5674

5775
// Lookup the controller instance for the specified sidNav instance
76+
var self;
77+
var errorMsg = "SideNav '" + handle + "' is not available!";
5878
var instance = $mdComponentRegistry.get(handle);
79+
5980
if(!instance) {
6081
$mdComponentRegistry.notFoundError(handle);
6182
}
6283

63-
return {
84+
return self = {
85+
// -----------------
86+
// Sync methods
87+
// -----------------
6488
isOpen: function() {
6589
return instance && instance.isOpen();
6690
},
6791
isLockedOpen: function() {
6892
return instance && instance.isLockedOpen();
6993
},
94+
// -----------------
95+
// Async methods
96+
// -----------------
7097
toggle: function() {
7198
return instance ? instance.toggle() : $q.reject(errorMsg);
7299
},
@@ -75,8 +102,24 @@ function SidenavService($mdComponentRegistry, $q) {
75102
},
76103
close: function() {
77104
return instance ? instance.close() : $q.reject(errorMsg);
105+
},
106+
then : function( callbackFn ) {
107+
var promise = instance ? $q.when(instance) : waitForInstance();
108+
return promise.then( callbackFn || angular.noop );
78109
}
79110
};
111+
112+
/**
113+
* Deferred lookup of component instance using $component registry
114+
*/
115+
function waitForInstance() {
116+
return $mdComponentRegistry
117+
.when(handle)
118+
.then(function( it ){
119+
instance = it;
120+
return it;
121+
});
122+
}
80123
};
81124
}
82125

@@ -162,7 +205,10 @@ function SidenavDirective($timeout, $animate, $parse, $log, $mdMedia, $mdConstan
162205
var isLockedOpenParsed = $parse(attr.mdIsLockedOpen);
163206
var isLocked = function() {
164207
return isLockedOpenParsed(scope.$parent, {
165-
$media: function(arg) { $log.warn("$media is deprecated for is-locked-open. Use $mdMedia instead."); return $mdMedia(arg); },
208+
$media: function(arg) {
209+
$log.warn("$media is deprecated for is-locked-open. Use $mdMedia instead.");
210+
return $mdMedia(arg);
211+
},
166212
$mdMedia: $mdMedia
167213
});
168214
};
@@ -311,13 +357,17 @@ function SidenavController($scope, $element, $attrs, $mdComponentRegistry, $q) {
311357

312358
// Use Default internal method until overridden by directive postLink
313359

314-
self.$toggleOpen = function() { return $q.when($scope.isOpen); };
360+
// Synchronous getters
315361
self.isOpen = function() { return !!$scope.isOpen; };
316362
self.isLockedOpen = function() { return !!$scope.isLockedOpen; };
363+
364+
// Async actions
317365
self.open = function() { return self.$toggleOpen( true ); };
318366
self.close = function() { return self.$toggleOpen( false ); };
319367
self.toggle = function() { return self.$toggleOpen( !$scope.isOpen ); };
320368

369+
self.$toggleOpen = function() { return $q.when($scope.isOpen); };
370+
321371
self.destroy = $mdComponentRegistry.register(self, $attrs.mdComponentId);
322372
}
323373

src/components/sidenav/sidenav.spec.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,15 @@ describe('mdSidenav', function() {
205205
});
206206

207207
describe('$mdSidenav Service', function() {
208+
var $rootScope, $timeout;
209+
210+
211+
beforeEach( inject(function(_$rootScope_,_$timeout_) {
212+
$rootScope = _$rootScope_;
213+
$timeout = _$timeout_;
214+
}));
215+
216+
208217
it('should grab instance', inject(function($mdSidenav) {
209218
var el = setup('md-component-id="left"');
210219
var scope = el.isolateScope();
@@ -253,6 +262,28 @@ describe('mdSidenav', function() {
253262
expect(instance.isOpen()).toBe(false);
254263
expect(instance.isLockedOpen()).toBe(true);
255264
}));
265+
266+
it('should find a deferred instantiation', inject(function($mdSidenav) {
267+
var instance;
268+
269+
// Lookup deferred (not existing) instance
270+
$mdSidenav('left').then( function(inst) { instance = inst; });
271+
expect(instance).toBeUndefined();
272+
273+
// Instantiate `left` sidenav component
274+
var el = setup('md-component-id="left"');
275+
276+
$timeout.flush();
277+
expect(instance).toBeTruthy();
278+
expect(instance.isOpen()).toBeFalsy();
279+
280+
// Lookup instance still available in the component registry
281+
instance = undefined;
282+
instance = $mdSidenav('left');
283+
284+
expect(instance).toBeTruthy();
285+
286+
}));
256287
});
257288

258289
});

0 commit comments

Comments
 (0)