@@ -19,7 +19,7 @@ function $RouteProvider(){
19
19
* @methodOf angular.module.ng.$routeProvider
20
20
*
21
21
* @param {string } path Route path (matched against `$location.path`). If `$location.path`
22
- * contains redudant trailing slash or is missing one, the route will still match and the
22
+ * contains redundant trailing slash or is missing one, the route will still match and the
23
23
* `$location.path` will be updated to add or drop the trailing slash to exacly match the
24
24
* route definition.
25
25
* @param {Object } route Mapping information to be assigned to `$route.current` on route
@@ -32,6 +32,17 @@ function $RouteProvider(){
32
32
* - `template` – `{string=}` – path to an html template that should be used by
33
33
* {@link angular.module.ng.$compileProvider.directive.ngView ngView} or
34
34
* {@link angular.module.ng.$compileProvider.directive.ngInclude ngInclude} directives.
35
+ * - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
36
+ * be injected into the controller. If any of these dependencies are promises, they will be
37
+ * resolved and converted to a value before the controller is instantiated and the
38
+ * `$aftreRouteChange` event is fired. The map object is:
39
+ *
40
+ * - `key` – `{string}`: a name of a dependency to be injected into the controller.
41
+ * - `factory` - `{string|function}`: If `string` then it is an alias for a service.
42
+ * Otherwise if function, then it is {@link api/angular.module.AUTO.$injector#invoke injected}
43
+ * and the return value is treated as the dependency. If the result is a promise, it is resolved
44
+ * before its value is injected into the controller.
45
+ *
35
46
* - `redirectTo` – {(string|function())=} – value to update
36
47
* {@link angular.module.ng.$location $location} path with and trigger route redirection.
37
48
*
@@ -89,8 +100,8 @@ function $RouteProvider(){
89
100
} ;
90
101
91
102
92
- this . $get = [ '$rootScope' , '$location' , '$routeParams' ,
93
- function ( $rootScope , $location , $routeParams ) {
103
+ this . $get = [ '$rootScope' , '$location' , '$routeParams' , '$q' , '$injector' , '$http' , '$templateCache' ,
104
+ function ( $rootScope , $location , $routeParams , $q , $injector , $http , $templateCache ) {
94
105
95
106
/**
96
107
* @ngdoc object
@@ -99,6 +110,16 @@ function $RouteProvider(){
99
110
* @requires $routeParams
100
111
*
101
112
* @property {Object } current Reference to the current route definition.
113
+ * The route definition contains:
114
+ *
115
+ * - `controller`: The controller constructor as define in route definition.
116
+ * - `locals`: A map of locals which is used by {@link angular.module.ng.$controller $controller} service for
117
+ * controller instantiation. The `locals` contain
118
+ * the resolved values of the `resolve` map. Additionally the `locals` also contain:
119
+ *
120
+ * - `$scope` - The current route scope.
121
+ * - `$template` - The current route template HTML.
122
+ *
102
123
* @property {Array.<Object> } routes Array of all configured routes.
103
124
*
104
125
* @description
@@ -153,7 +174,15 @@ function $RouteProvider(){
153
174
angular.module('ngView', [], function($routeProvider, $locationProvider) {
154
175
$routeProvider.when('/Book/:bookId', {
155
176
template: 'book.html',
156
- controller: BookCntl
177
+ controller: BookCntl,
178
+ resolve: {
179
+ // I will cause a 1 second delay
180
+ delay: function($q, $timeout) {
181
+ var delay = $q.defer();
182
+ $timeout(delay.resolve, 1000);
183
+ return delay.promise;
184
+ }
185
+ }
157
186
});
158
187
$routeProvider.when('/Book/:bookId/ch/:chapterId', {
159
188
template: 'chapter.html',
@@ -190,6 +219,7 @@ function $RouteProvider(){
190
219
expect(content).toMatch(/Chapter Id\: 1/);
191
220
192
221
element('a:contains("Scarlet")').click();
222
+ sleep(2); // promises are not part of scenario waiting
193
223
content = element('.doc-example-live [ng-view]').text();
194
224
expect(content).toMatch(/controller\: BookCntl/);
195
225
expect(content).toMatch(/Book Id\: Scarlet/);
@@ -204,7 +234,11 @@ function $RouteProvider(){
204
234
* @eventOf angular.module.ng.$route
205
235
* @eventType broadcast on root scope
206
236
* @description
207
- * Broadcasted before a route change.
237
+ * Broadcasted before a route change. At this point the route services starts
238
+ * resolving all of the dependencies needed for the route change to occurs.
239
+ * Typically this involves fetching the view template as well as any dependencies
240
+ * defined in `resolve` route property. Once all of the dependencies are resolved
241
+ * `$afterRouteChange` is fired.
208
242
*
209
243
* @param {Route } next Future route information.
210
244
* @param {Route } current Current route information.
@@ -216,12 +250,27 @@ function $RouteProvider(){
216
250
* @eventOf angular.module.ng.$route
217
251
* @eventType broadcast on root scope
218
252
* @description
219
- * Broadcasted after a route change.
253
+ * Broadcasted after a route dependencies are resolved.
254
+ * {@link angular.module.ng.$compileProvider.directive.ngView ngView} listens for the directive
255
+ * to instantiate the controller and render the view.
220
256
*
221
257
* @param {Route } current Current route information.
222
258
* @param {Route } previous Previous route information.
223
259
*/
224
260
261
+ /**
262
+ * @ngdoc event
263
+ * @name angular.module.ng.$route#$routeChangeError
264
+ * @eventOf angular.module.ng.$route
265
+ * @eventType broadcast on root scope
266
+ * @description
267
+ * Broadcasted if any of the resolve promises are rejected.
268
+ *
269
+ * @param {Route } current Current route information.
270
+ * @param {Route } previous Previous route information.
271
+ * @param {Route } rejection Rejection of the promise. Usually the error of the failed promise.
272
+ */
273
+
225
274
/**
226
275
* @ngdoc event
227
276
* @name angular.module.ng.$route#$routeUpdate
@@ -245,7 +294,7 @@ function $RouteProvider(){
245
294
* @methodOf angular.module.ng.$route
246
295
*
247
296
* @description
248
- * Causes `$route` service to reload theR current route even if
297
+ * Causes `$route` service to reload the current route even if
249
298
* {@link angular.module.ng.$location $location} hasn't changed.
250
299
*
251
300
* As a result of that, {@link angular.module.ng.$compileProvider.directive.ngView ngView}
@@ -309,11 +358,48 @@ function $RouteProvider(){
309
358
$location . url ( next . redirectTo ( next . pathParams , $location . path ( ) , $location . search ( ) ) )
310
359
. replace ( ) ;
311
360
}
312
- } else {
313
- copy ( next . params , $routeParams ) ;
314
361
}
315
362
}
316
- $rootScope . $broadcast ( '$afterRouteChange' , next , last ) ;
363
+
364
+ $q . when ( next ) .
365
+ then ( function ( ) {
366
+ if ( next ) {
367
+ var keys = [ ] ,
368
+ values = [ ] ;
369
+
370
+ forEach ( next . resolve || { } , function ( value , key ) {
371
+ keys . push ( key ) ;
372
+ values . push ( isFunction ( value ) ? $injector . invoke ( value ) : $injector . get ( value ) ) ;
373
+ } ) ;
374
+ if ( next . template ) {
375
+ keys . push ( '$template' ) ;
376
+ values . push ( $http .
377
+ get ( next . template , { cache : $templateCache } ) .
378
+ then ( function ( response ) { return response . data ; } ) ) ;
379
+ }
380
+ return $q . all ( values ) . then ( function ( values ) {
381
+ var locals = { } ;
382
+ forEach ( values , function ( value , index ) {
383
+ locals [ keys [ index ] ] = value ;
384
+ } ) ;
385
+ return locals ;
386
+ } ) ;
387
+ }
388
+ } ) .
389
+ // after route change
390
+ then ( function ( locals ) {
391
+ if ( next == $route . current ) {
392
+ if ( next ) {
393
+ next . locals = locals ;
394
+ copy ( next . params , $routeParams ) ;
395
+ }
396
+ $rootScope . $broadcast ( '$afterRouteChange' , next , last ) ;
397
+ }
398
+ } , function ( error ) {
399
+ if ( next == $route . current ) {
400
+ $rootScope . $broadcast ( '$routeChangeError' , next , last , error ) ;
401
+ }
402
+ } ) ;
317
403
}
318
404
}
319
405
0 commit comments