X Tutup
Skip to content

Commit d4a4d81

Browse files
fix(angular1_router): support templateUrl components
1 parent e7470d5 commit d4a4d81

File tree

5 files changed

+79
-48
lines changed

5 files changed

+79
-48
lines changed

modules/angular1_router/src/ng_outlet.ts

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ function ngOutletDirective($animate, $q: ng.IQService, $router) {
145145
}
146146

147147
activate(instruction) {
148-
let previousInstruction = this.currentInstruction;
148+
this.previousInstruction = this.currentInstruction;
149149
this.currentInstruction = instruction;
150150

151151
let componentName = this.controller.$$componentName = instruction.componentType;
@@ -154,13 +154,14 @@ function ngOutletDirective($animate, $q: ng.IQService, $router) {
154154
throw new Error('Component is not a string for ' + instruction.urlPath);
155155
}
156156

157-
this.controller.$$routeParams = instruction.params;
158157
this.controller.$$template =
159158
'<' + dashCase(componentName) + ' router="$$router"></' + dashCase(componentName) + '>';
160159
this.controller.$$router = this.router.childRouter(instruction.componentType);
160+
this.controller.$$outlet = this;
161161

162162
let newScope = scope.$new();
163163
newScope.$$router = this.controller.$$router;
164+
this.deferredActivation = $q.defer();
164165

165166
let clone = $transclude(newScope, clone => {
166167
$animate.enter(clone, null, this.currentElement || element);
@@ -169,15 +170,7 @@ function ngOutletDirective($animate, $q: ng.IQService, $router) {
169170

170171
this.currentElement = clone;
171172
this.currentScope = newScope;
172-
173-
// TODO: prefer the other directive retrieving the controller
174-
// by debug mode
175-
this.currentController = this.currentElement.children().eq(0).controller(componentName);
176-
177-
if (this.currentController && this.currentController.$routerOnActivate) {
178-
return this.currentController.$routerOnActivate(instruction, previousInstruction);
179-
}
180-
return $q.when();
173+
return this.deferredActivation.promise;
181174
}
182175
}
183176

@@ -200,21 +193,32 @@ function ngOutletFillContentDirective($compile) {
200193
link: (scope, element, attrs, ctrl) => {
201194
let template = ctrl.$$template;
202195
element.html(template);
203-
let link = $compile(element.contents());
204-
link(scope);
196+
$compile(element.contents())(scope);
197+
}
198+
};
199+
}
200+
205201

206-
// TODO: move to primary directive
207-
let componentInstance = scope[ctrl.$$componentName];
208-
if (componentInstance) {
209-
ctrl.$$currentComponent = componentInstance;
210202

211-
componentInstance.$router = ctrl.$$router;
212-
componentInstance.$routeParams = ctrl.$$routeParams;
203+
function routerTriggerDirective($q) {
204+
return {
205+
require: '^ngOutlet',
206+
priority: -1000,
207+
link: function(scope, element, attr, ngOutletCtrl) {
208+
var promise = $q.when();
209+
var outlet = ngOutletCtrl.$$outlet;
210+
var currentComponent = outlet.currentController =
211+
element.controller(ngOutletCtrl.$$componentName);
212+
if (currentComponent.$routerOnActivate) {
213+
promise = $q.when(currentComponent.$routerOnActivate(outlet.currentInstruction,
214+
outlet.previousInstruction));
213215
}
216+
promise.then(outlet.deferredActivation.resolve, outlet.deferredActivation.reject);
214217
}
215218
};
216219
}
217220

221+
218222
/**
219223
* @name ngLink
220224
* @description
@@ -289,7 +293,8 @@ function dashCase(str: string): string {
289293
angular.module('ngComponentRouter', [])
290294
.directive('ngOutlet', ['$animate', '$q', '$router', ngOutletDirective])
291295
.directive('ngOutlet', ['$compile', ngOutletFillContentDirective])
292-
.directive('ngLink', ['$router', '$parse', ngLinkDirective]);
296+
.directive('ngLink', ['$router', '$parse', ngLinkDirective])
297+
.directive('router', ['$q', routerTriggerDirective]);
293298

294299
/*
295300
* A module for inspecting controller constructors

modules/angular1_router/src/ng_route_shim.js

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -116,53 +116,41 @@
116116
console.warn('Route for "' + path + '" should use "controllerAs".');
117117
}
118118

119-
var directiveName = routeObjToRouteName(routeCopy, path);
119+
var componentName = routeObjToRouteName(routeCopy, path);
120120

121-
if (!directiveName) {
121+
if (!componentName) {
122122
throw new Error('Could not determine a name for route "' + path + '".');
123123
}
124124

125-
routeDefinition.component = directiveName;
126-
routeDefinition.name = route.name || upperCase(directiveName);
125+
routeDefinition.component = componentName;
126+
routeDefinition.name = route.name || upperCase(componentName);
127127

128128
var directiveController = routeCopy.controller;
129129

130-
var directiveDefinition = {
131-
scope: false,
130+
var componentDefinition = {
132131
controller: directiveController,
133-
controllerAs: routeCopy.controllerAs,
134-
templateUrl: routeCopy.templateUrl,
135-
template: routeCopy.template
136-
};
132+
controllerAs: routeCopy.controllerAs
137133

138-
var directiveFactory = function () {
139-
return directiveDefinition;
140134
};
135+
if (routeCopy.templateUrl) componentDefinition.templateUrl = routeCopy.templateUrl;
136+
if (routeCopy.template) componentDefinition.template = routeCopy.template;
137+
141138

142139
// if we have route resolve options, prepare a wrapper controller
143140
if (directiveController && routeCopy.resolve) {
144141
var originalController = directiveController;
145142
var resolvedLocals = {};
146143

147-
directiveDefinition.controller = ['$injector', '$scope', function ($injector, $scope) {
144+
componentDefinition.controller = ['$injector', '$scope', function ($injector, $scope) {
148145
var locals = angular.extend({
149146
$scope: $scope
150147
}, resolvedLocals);
151148

152-
var ctrl = $injector.instantiate(originalController, locals);
153-
154-
if (routeCopy.controllerAs) {
155-
locals.$scope[routeCopy.controllerAs] = ctrl;
156-
}
157-
158-
return ctrl;
149+
return $injector.instantiate(originalController, locals);
159150
}];
160151

161-
// we take care of controllerAs in the directive controller wrapper
162-
delete directiveDefinition.controllerAs;
163-
164152
// we resolve the locals in a canActivate block
165-
directiveFactory.$canActivate = function() {
153+
componentDefinition.$canActivate = function() {
166154
var locals = angular.extend({}, routeCopy.resolve);
167155

168156
angular.forEach(locals, function(value, key) {
@@ -179,7 +167,7 @@
179167
}
180168

181169
// register the dynamically created directive
182-
$compileProvider.directive(directiveName, directiveFactory);
170+
$compileProvider.component(componentName, componentDefinition);
183171
}
184172
if (subscriptionFn) {
185173
subscriptionFn(routeDefinition);

modules/angular1_router/test/integration/animation_spec.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ describe('ngOutlet animations', function () {
2525
});
2626

2727
registerComponent('userCmp', {
28-
template: '<div>hello {{userCmp.$routeParams.name}}</div>'
28+
template: '<div>hello {{userCmp.$routeParams.name}}</div>',
29+
$routerOnActivate: function(next) {
30+
this.$routeParams = next.params;
31+
}
2932
});
3033
});
3134

modules/angular1_router/test/integration/navigation_spec.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ describe('navigation', function () {
2222
});
2323

2424
registerDirective('userCmp', {
25-
template: '<div>hello {{userCmp.$routeParams.name}}</div>'
25+
template: '<div>hello {{userCmp.$routeParams.name}}</div>',
26+
$routerOnActivate: function(next) {
27+
this.$routeParams = next.params;
28+
}
2629
});
2730
registerDirective('oneCmp', {
2831
template: '<div>{{oneCmp.number}}</div>',

modules/angular1_router/test/integration/router_spec.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,32 @@ describe('router', function () {
9595
expect(elt.text()).toBe('Home (true)');
9696
}));
9797

98+
it('should work with a templateUrl component', inject(function($location, $httpBackend) {
99+
var $routerOnActivate = jasmine.createSpy('$routerOnActivate');
100+
$httpBackend.expectGET('homeCmp.html').respond('Home');
101+
registerComponent('homeCmp', {
102+
templateUrl: 'homeCmp.html',
103+
$routerOnActivate: $routerOnActivate
104+
});
105+
106+
registerComponent('app', {
107+
template: '<div ng-outlet></div>',
108+
$routeConfig: [
109+
{ path: '/', component: 'homeCmp' }
110+
]
111+
});
112+
113+
compile('<app></app>');
114+
115+
$location.path('/');
116+
$rootScope.$digest();
117+
$httpBackend.flush();
118+
var homeElement = elt.find('home-cmp');
119+
expect(homeElement.text()).toBe('Home');
120+
expect($routerOnActivate).toHaveBeenCalled();
121+
}));
122+
123+
98124
function registerDirective(name, options) {
99125
function factory() {
100126
return {
@@ -111,9 +137,15 @@ describe('router', function () {
111137

112138
var definition = {
113139
bindings: options.bindings,
114-
template: options.template || '',
115140
controller: getController(options),
141+
};
142+
if (options.template) {
143+
definition.template = options.template;
116144
}
145+
if (options.templateUrl) {
146+
definition.templateUrl = options.templateUrl;
147+
}
148+
117149
applyStaticProperties(definition, options);
118150
$compileProvider.component(name, definition);
119151
}

0 commit comments

Comments
 (0)
X Tutup