Skip to content

Commit adef68b

Browse files
refactor(angular_1_router): remove directiveIntrospector
The directiveIntrospector was a bit of a hack to allow the router to read the `$routeConfig` annocation and `$routerCanActivate` hook from directives when they were registered. It turns out that if we put these properties on the component controller's constructor function (i.e. as static class methods) then we can simply use the `$injector` to access it as required. Currently, people put the properties directly on their component definition objects. In Angular 1.5.1, we will copy these properties onto the controller constructor to maintain a simple migration path. But going forward it may be better to encourage people to add the properties directly to the controller constructor.
1 parent 14f0e9a commit adef68b

File tree

3 files changed

+41
-103
lines changed

3 files changed

+41
-103
lines changed

modules/angular1_router/src/module_template.js

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ angular.module('ngComponentRouter').
44
// Because Angular 1 has no notion of a root component, we use an object with unique identity
55
// to represent this. Can be overloaded with a component name
66
value('$routerRootComponent', new Object()).
7-
factory('$rootRouter', ['$q', '$location', '$$directiveIntrospector', '$browser', '$rootScope', '$injector', '$routerRootComponent', routerFactory]);
7+
factory('$rootRouter', ['$q', '$location', '$browser', '$rootScope', '$injector', '$routerRootComponent', routerFactory]);
88

9-
function routerFactory($q, $location, $$directiveIntrospector, $browser, $rootScope, $injector, $routerRootComponent) {
9+
function routerFactory($q, $location, $browser, $rootScope, $injector, $routerRootComponent) {
1010

1111
// When this file is processed, the line below is replaced with
1212
// the contents of `../lib/facades.es5`.
@@ -23,11 +23,24 @@ function routerFactory($q, $location, $$directiveIntrospector, $browser, $rootSc
2323
// the contents of the compiled TypeScript classes.
2424
//{{SHARED_CODE}}
2525

26+
function getComponentConstructor(name) {
27+
var serviceName = name + 'Directive';
28+
if ($injector.has(serviceName)) {
29+
var definitions = $injector.get(serviceName);
30+
if (definitions.length > 1) {
31+
throw new BaseException('too many directives named "' + name + '"');
32+
}
33+
return definitions[0].controller;
34+
} else {
35+
throw new BaseException('directive "' + name + '" is not registered');
36+
}
37+
}
38+
2639
//TODO: this is a hack to replace the exiting implementation at run-time
2740
exports.getCanActivateHook = function (directiveName) {
28-
var factory = $$directiveIntrospector.getTypeByName(directiveName);
29-
return factory && factory.$canActivate && function (next, prev) {
30-
return $injector.invoke(factory.$canActivate, null, {
41+
var controller = getComponentConstructor(directiveName);
42+
return controller.$canActivate && function (next, prev) {
43+
return $injector.invoke(controller.$canActivate, null, {
3144
$nextInstruction: next,
3245
$prevInstruction: prev
3346
});
@@ -45,17 +58,32 @@ function routerFactory($q, $location, $$directiveIntrospector, $browser, $rootSc
4558
var RouteRegistry = exports.RouteRegistry;
4659
var RootRouter = exports.RootRouter;
4760

61+
// Override this method to actually get hold of the child routes
62+
RouteRegistry.prototype.configFromComponent = function (component) {
63+
var that = this;
64+
if (isString(component)) {
65+
// Don't read the annotations component a type more than once –
66+
// this prevents an infinite loop if a component routes recursively.
67+
if (this._rules.has(component)) {
68+
return;
69+
}
70+
var controller = getComponentConstructor(component);
71+
if (angular.isArray(controller.$routeConfig)) {
72+
controller.$routeConfig.forEach(function (config) {
73+
var loader = config.loader;
74+
if (isPresent(loader)) {
75+
config = angular.extend({}, config, { loader: () => $injector.invoke(loader) });
76+
}
77+
that.config(component, config);
78+
});
79+
}
80+
}
81+
82+
}
83+
4884
var registry = new RouteRegistry($routerRootComponent);
4985
var location = new Location();
5086

51-
$$directiveIntrospector(function (name, factory) {
52-
if (angular.isArray(factory.$routeConfig)) {
53-
factory.$routeConfig.forEach(function (config) {
54-
registry.config(name, config);
55-
});
56-
}
57-
});
58-
5987
var router = new RootRouter(registry, location, $routerRootComponent);
6088
$rootScope.$watch(function () { return $location.url(); }, function (path) {
6189
if (router.lastNavigationAttempt !== path) {

modules/angular1_router/src/ng_outlet.ts

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,6 @@
11
///<reference path="../typings/angularjs/angular.d.ts"/>
22

3-
/*
4-
* decorates $compileProvider so that we have access to routing metadata
5-
*/
6-
function compilerProviderDecorator($compileProvider,
7-
$$directiveIntrospectorProvider: DirectiveIntrospectorProvider) {
8-
let directive = $compileProvider.directive;
9-
$compileProvider.directive = function(name: string, factory: Function) {
10-
$$directiveIntrospectorProvider.register(name, factory);
11-
return directive.apply(this, arguments);
12-
};
13-
}
143

15-
/*
16-
* private service that holds route mappings for each controller
17-
*/
18-
class DirectiveIntrospectorProvider {
19-
private directiveBuffer: any[] = [];
20-
private directiveFactoriesByName: {[name: string]: Function} = {};
21-
private onDirectiveRegistered: (name: string, factory: Function) => any = null;
22-
23-
register(name: string, factory: Function) {
24-
if (angular.isArray(factory)) {
25-
factory = factory[factory.length - 1];
26-
}
27-
this.directiveFactoriesByName[name] = factory;
28-
if (this.onDirectiveRegistered) {
29-
this.onDirectiveRegistered(name, factory);
30-
} else {
31-
this.directiveBuffer.push({name: name, factory: factory});
32-
}
33-
}
34-
35-
$get() {
36-
let fn: any = newOnControllerRegistered => {
37-
this.onDirectiveRegistered = newOnControllerRegistered;
38-
while (this.directiveBuffer.length > 0) {
39-
let directive = this.directiveBuffer.pop();
40-
this.onDirectiveRegistered(directive.name, directive.factory);
41-
}
42-
};
43-
44-
fn.getTypeByName = name => this.directiveFactoriesByName[name];
45-
46-
return fn;
47-
}
48-
}
494

505
/**
516
* @name ngOutlet
@@ -303,10 +258,3 @@ angular.module('ngComponentRouter', [])
303258
.directive('ngOutlet', ['$compile', ngOutletFillContentDirective])
304259
.directive('ngLink', ['$rootRouter', '$parse', ngLinkDirective])
305260
.directive('$router', ['$q', routerTriggerDirective]);
306-
307-
/*
308-
* A module for inspecting controller constructors
309-
*/
310-
angular.module('ng')
311-
.provider('$$directiveIntrospector', DirectiveIntrospectorProvider)
312-
.config(['$compileProvider', '$$directiveIntrospectorProvider', compilerProviderDecorator]);

modules/angular1_router/test/directive_introspector_spec.js

Lines changed: 0 additions & 38 deletions
This file was deleted.

0 commit comments

Comments
 (0)