fix(router): preserve specificity for redirects

Previously when comparing which of multiple possible routes to choose in
an ambiguous case, we looked at the specificity of the target of redirect
matches rather than the original match. This meant that if a redirect
used a whilecard, but redirected to a target that was a static path,
we'd cound the static path's specificity instead of the wildcard.

This change stores the specificity of the redirect on the RedirectInstruction.

Closes #5933
This commit is contained in:
Brian Ford 2015-12-15 15:58:04 -08:00
parent 9d28147acb
commit a038bb9ae3
4 changed files with 30 additions and 3 deletions

View File

@ -281,9 +281,11 @@ export class UnresolvedInstruction extends Instruction {
export class RedirectInstruction extends ResolvedInstruction {
constructor(component: ComponentInstruction, child: Instruction,
auxInstruction: {[key: string]: Instruction}) {
auxInstruction: {[key: string]: Instruction}, private _specificity: string) {
super(component, child, auxInstruction);
}
get specificity(): string { return this._specificity; }
}

View File

@ -205,7 +205,7 @@ export class RouteRegistry {
var instruction =
this.generate(candidate.redirectTo, ancestorInstructions.concat([null]));
return new RedirectInstruction(instruction.component, instruction.child,
instruction.auxInstruction);
instruction.auxInstruction, candidate.specificity);
}
}));

View File

@ -10,6 +10,12 @@ import {
} from 'angular2/router';
import {PromiseWrapper} from 'angular2/src/facade/async';
@Component({selector: 'goodbye-cmp', template: `{{farewell}}`})
export class GoodbyeCmp {
farewell: string;
constructor() { this.farewell = 'goodbye'; }
}
@Component({selector: 'hello-cmp', template: `{{greeting}}`})
export class HelloCmp {
greeting: string;

View File

@ -25,7 +25,7 @@ import {
} from 'angular2/src/router/route_config_decorator';
import {TEST_ROUTER_PROVIDERS, RootCmp, compile} from './util';
import {HelloCmp, RedirectToParentCmp} from './impl/fixture_components';
import {HelloCmp, GoodbyeCmp, RedirectToParentCmp} from './impl/fixture_components';
var cmpInstanceCount;
var childCmpInstanceCount;
@ -117,5 +117,24 @@ export function main() {
async.done();
});
}));
it('should not redirect when redirect is less specific than other matching routes',
inject([AsyncTestCompleter, Location], (async, location) => {
compile(tcb)
.then((rtc) => {rootTC = rtc})
.then((_) => rtr.config([
new Route({path: '/foo', component: HelloCmp, name: 'Hello'}),
new Route({path: '/:param', component: GoodbyeCmp, name: 'Goodbye'}),
new Redirect({path: '/*rest', redirectTo: ['/Hello']})
]))
.then((_) => rtr.navigateByUrl('/bye'))
.then((_) => {
rootTC.detectChanges();
expect(rootTC.debugElement.nativeElement).toHaveText('goodbye');
expect(location.urlChanges).toEqual(['/bye']);
async.done();
});
}));
});
}