Skip to content

Commit 5e49d7e

Browse files
committed
fix(router): load route config from async instructions
Previously, async routes generated from links would not load the configs of their resolved components, which led to broken links in the children of the async instruction's component. This commit fixes the bookkeeping in the Router to correctly load the configs. Fixes internal b/23791558 Closes angular#4146
1 parent 4c2fb1f commit 5e49d7e

File tree

4 files changed

+36
-5
lines changed

4 files changed

+36
-5
lines changed

modules/angular2/src/router/route_registry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,9 @@ export class RouteRegistry {
249249
}
250250
lastInstructionIsTerminal = lastInstruction.component.terminal;
251251
}
252-
if (!lastInstructionIsTerminal) {
252+
if (isPresent(componentCursor) && !lastInstructionIsTerminal) {
253253
throw new BaseException(
254-
`Link "${ListWrapper.toJSON(linkParams)}" does not resolve to a terminal instruction.`);
254+
`Link "${ListWrapper.toJSON(linkParams)}" does not resolve to a terminal or async instruction.`);
255255
}
256256
}
257257

modules/angular2/src/router/router.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ export class Router {
217217
_settleInstruction(instruction: Instruction): Promise<any> {
218218
var unsettledInstructions: Array<Promise<any>> = [];
219219
if (isBlank(instruction.component.componentType)) {
220-
unsettledInstructions.push(instruction.component.resolveComponentType());
220+
unsettledInstructions.push(instruction.component.resolveComponentType().then(
221+
(type: Type) => { this.registry.configFromComponent(type); }));
221222
}
222223
if (isPresent(instruction.child)) {
223224
unsettledInstructions.push(this._settleInstruction(instruction.child));

modules/angular2/test/router/integration/router_link_spec.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
} from 'angular2/test_lib';
1818

1919
import {NumberWrapper} from 'angular2/src/core/facade/lang';
20+
import {PromiseWrapper} from 'angular2/src/core/facade/async';
2021

2122
import {bind, Component, DirectiveResolver, View} from 'angular2/core';
2223

@@ -29,6 +30,7 @@ import {
2930
Pipeline,
3031
RouterLink,
3132
RouterOutlet,
33+
AsyncRoute,
3234
Route,
3335
RouteParams,
3436
RouteConfig,
@@ -96,7 +98,6 @@ export function main() {
9698
}));
9799

98100

99-
100101
it('should generate link hrefs with params', inject([AsyncTestCompleter], (async) => {
101102
compile('<a href="hello" [router-link]="[\'./user\', {name: name}]">{{name}}</a>')
102103
.then((_) => router.config(
@@ -128,6 +129,31 @@ export function main() {
128129
});
129130
}));
130131

132+
it('should generate link hrefs when asynchronously loaded',
133+
inject([AsyncTestCompleter], (async) => {
134+
compile()
135+
.then((_) => router.config([
136+
new AsyncRoute({
137+
path: '/child-with-grandchild/...',
138+
loader: parentCmpLoader,
139+
as: 'child-with-grandchild'
140+
})
141+
]))
142+
.then((_) => {
143+
// TODO: refactor when https://github.com/angular/angular/pull/4074 lands
144+
var instruction = router.generate(['/child-with-grandchild']);
145+
return router.navigateInstruction(instruction);
146+
})
147+
.then((_) => {
148+
rootTC.detectChanges();
149+
expect(DOM.getAttribute(
150+
rootTC.componentViewChildren[1].componentViewChildren[0].nativeElement,
151+
'href'))
152+
.toEqual('/child-with-grandchild/grandchild');
153+
async.done();
154+
});
155+
}));
156+
131157
it('should generate relative links preserving the existing parent route',
132158
inject([AsyncTestCompleter], (async) => {
133159
compile()
@@ -319,6 +345,10 @@ class HelloCmp {
319345
class Hello2Cmp {
320346
}
321347

348+
function parentCmpLoader() {
349+
return PromiseWrapper.resolve(ParentCmp);
350+
}
351+
322352
@Component({selector: 'parent-cmp'})
323353
@View({
324354
template: `{ <a [router-link]="['./grandchild']" class="grandchild-link">Grandchild</a>

modules/angular2/test/router/route_registry_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ export function main() {
235235
registry.config(RootHostCmp,
236236
new Route({path: '/first/...', component: DummyParentCmp, as: 'first'}));
237237
expect(() => { registry.generate(['first'], RootHostCmp); })
238-
.toThrowError('Link "["first"]" does not resolve to a terminal instruction.');
238+
.toThrowError('Link "["first"]" does not resolve to a terminal or async instruction.');
239239
});
240240

241241
it('should match matrix params on child components and query params on the root component',

0 commit comments

Comments
 (0)