2015-05-29 17:58:41 -04:00
|
|
|
import {
|
|
|
|
AsyncTestCompleter,
|
|
|
|
describe,
|
|
|
|
proxy,
|
|
|
|
it,
|
|
|
|
iit,
|
|
|
|
ddescribe,
|
|
|
|
expect,
|
|
|
|
inject,
|
|
|
|
beforeEach,
|
refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
{ path: '/foo', redirectTo: '/bar' },
{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
{ path: '/foo', redirectTo: ['Bar'] },
{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
{ path: '/tab', redirectTo: '/tab/users' }
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
2015-11-23 21:07:37 -05:00
|
|
|
beforeEachProviders
|
2015-10-13 03:29:13 -04:00
|
|
|
} from 'angular2/testing_internal';
|
2015-08-26 14:41:41 -04:00
|
|
|
import {SpyRouterOutlet} from './spies';
|
2015-11-06 20:34:07 -05:00
|
|
|
import {Type} from 'angular2/src/facade/lang';
|
|
|
|
import {Promise, PromiseWrapper, ObservableWrapper} from 'angular2/src/facade/async';
|
|
|
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
2015-08-14 15:31:56 -04:00
|
|
|
|
2015-05-29 17:58:41 -04:00
|
|
|
import {Router, RootRouter} from 'angular2/src/router/router';
|
|
|
|
import {SpyLocation} from 'angular2/src/mock/location_mock';
|
|
|
|
import {Location} from 'angular2/src/router/location';
|
|
|
|
|
refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
{ path: '/foo', redirectTo: '/bar' },
{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
{ path: '/foo', redirectTo: ['Bar'] },
{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
{ path: '/tab', redirectTo: '/tab/users' }
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
2015-11-23 21:07:37 -05:00
|
|
|
import {RouteRegistry, ROUTER_PRIMARY_COMPONENT} from 'angular2/src/router/route_registry';
|
2015-12-07 19:05:57 -05:00
|
|
|
import {RouteConfig, AsyncRoute, Route, Redirect} from 'angular2/src/router/route_config_decorator';
|
2015-10-02 10:37:23 -04:00
|
|
|
import {DirectiveResolver} from 'angular2/src/core/linker/directive_resolver';
|
2015-05-29 17:58:41 -04:00
|
|
|
|
2015-10-11 01:11:13 -04:00
|
|
|
import {provide} from 'angular2/core';
|
2015-05-29 17:58:41 -04:00
|
|
|
|
|
|
|
export function main() {
|
|
|
|
describe('Router', () => {
|
|
|
|
var router, location;
|
|
|
|
|
refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
{ path: '/foo', redirectTo: '/bar' },
{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
{ path: '/foo', redirectTo: ['Bar'] },
{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
{ path: '/tab', redirectTo: '/tab/users' }
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
2015-11-23 21:07:37 -05:00
|
|
|
beforeEachProviders(() => [
|
2015-07-06 20:41:15 -04:00
|
|
|
RouteRegistry,
|
2015-05-29 17:58:41 -04:00
|
|
|
DirectiveResolver,
|
2015-10-12 14:30:34 -04:00
|
|
|
provide(Location, {useClass: SpyLocation}),
|
refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
{ path: '/foo', redirectTo: '/bar' },
{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
{ path: '/foo', redirectTo: ['Bar'] },
{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
{ path: '/tab', redirectTo: '/tab/users' }
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
2015-11-23 21:07:37 -05:00
|
|
|
provide(ROUTER_PRIMARY_COMPONENT, {useValue: AppCmp}),
|
|
|
|
provide(Router, {useClass: RootRouter})
|
2015-05-29 17:58:41 -04:00
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
beforeEach(inject([Router, Location], (rtr, loc) => {
|
|
|
|
router = rtr;
|
|
|
|
location = loc;
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
it('should navigate based on the initial URL state', inject([AsyncTestCompleter], (async) => {
|
|
|
|
var outlet = makeDummyOutlet();
|
|
|
|
|
2015-07-13 19:12:48 -04:00
|
|
|
router.config([new Route({path: '/', component: DummyComponent})])
|
2015-08-31 00:25:46 -04:00
|
|
|
.then((_) => router.registerPrimaryOutlet(outlet))
|
2015-05-29 17:58:41 -04:00
|
|
|
.then((_) => {
|
2015-08-31 00:25:46 -04:00
|
|
|
expect(outlet.spy('activate')).toHaveBeenCalled();
|
2015-05-29 17:58:41 -04:00
|
|
|
expect(location.urlChanges).toEqual([]);
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
it('should activate viewports and update URL on navigate',
|
|
|
|
inject([AsyncTestCompleter], (async) => {
|
|
|
|
var outlet = makeDummyOutlet();
|
|
|
|
|
2015-08-31 00:25:46 -04:00
|
|
|
router.registerPrimaryOutlet(outlet)
|
2015-07-13 19:12:48 -04:00
|
|
|
.then((_) => router.config([new Route({path: '/a', component: DummyComponent})]))
|
2015-09-09 00:41:56 -04:00
|
|
|
.then((_) => router.navigateByUrl('/a'))
|
2015-05-29 17:58:41 -04:00
|
|
|
.then((_) => {
|
2015-08-31 00:25:46 -04:00
|
|
|
expect(outlet.spy('activate')).toHaveBeenCalled();
|
2015-05-29 17:58:41 -04:00
|
|
|
expect(location.urlChanges).toEqual(['/a']);
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
2015-09-09 00:42:23 -04:00
|
|
|
it('should activate viewports and update URL when navigating via DSL',
|
|
|
|
inject([AsyncTestCompleter], (async) => {
|
|
|
|
var outlet = makeDummyOutlet();
|
|
|
|
|
|
|
|
router.registerPrimaryOutlet(outlet)
|
2015-10-25 05:30:27 -04:00
|
|
|
.then((_) => router.config(
|
|
|
|
[new Route({path: '/a', component: DummyComponent, name: 'A'})]))
|
2015-09-09 00:42:23 -04:00
|
|
|
.then((_) => router.navigate(['/A']))
|
|
|
|
.then((_) => {
|
|
|
|
expect(outlet.spy('activate')).toHaveBeenCalled();
|
|
|
|
expect(location.urlChanges).toEqual(['/a']);
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
2015-07-28 01:46:09 -04:00
|
|
|
it('should not push a history change on when navigate is called with skipUrlChange',
|
|
|
|
inject([AsyncTestCompleter], (async) => {
|
|
|
|
var outlet = makeDummyOutlet();
|
|
|
|
|
2015-08-31 00:25:46 -04:00
|
|
|
router.registerPrimaryOutlet(outlet)
|
2015-07-28 01:46:09 -04:00
|
|
|
.then((_) => router.config([new Route({path: '/b', component: DummyComponent})]))
|
2015-09-09 00:41:56 -04:00
|
|
|
.then((_) => router.navigateByUrl('/b', true))
|
2015-07-28 01:46:09 -04:00
|
|
|
.then((_) => {
|
2015-08-31 00:25:46 -04:00
|
|
|
expect(outlet.spy('activate')).toHaveBeenCalled();
|
2015-07-28 01:46:09 -04:00
|
|
|
expect(location.urlChanges).toEqual([]);
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
2015-12-07 19:05:57 -05:00
|
|
|
// See https://github.com/angular/angular/issues/5590
|
|
|
|
it('should replace history when triggered by a hashchange with a redirect',
|
|
|
|
inject([AsyncTestCompleter], (async) => {
|
|
|
|
var outlet = makeDummyOutlet();
|
|
|
|
|
|
|
|
router.registerPrimaryOutlet(outlet)
|
|
|
|
.then((_) => router.config([
|
|
|
|
new Redirect({path: '/a', redirectTo: ['B']}),
|
|
|
|
new Route({path: '/b', component: DummyComponent, name: 'B'})
|
|
|
|
]))
|
|
|
|
.then((_) => {
|
|
|
|
router.subscribe((_) => {
|
|
|
|
expect(location.urlChanges).toEqual(['hash: a', 'replace: /b']);
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
|
|
|
|
location.simulateHashChange('a');
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
it('should push history when triggered by a hashchange without a redirect',
|
|
|
|
inject([AsyncTestCompleter], (async) => {
|
|
|
|
var outlet = makeDummyOutlet();
|
|
|
|
|
|
|
|
router.registerPrimaryOutlet(outlet)
|
|
|
|
.then((_) => router.config([new Route({path: '/a', component: DummyComponent})]))
|
|
|
|
.then((_) => {
|
|
|
|
router.subscribe((_) => {
|
|
|
|
expect(location.urlChanges).toEqual(['hash: a']);
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
|
|
|
|
location.simulateHashChange('a');
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
2015-05-29 17:58:41 -04:00
|
|
|
it('should navigate after being configured', inject([AsyncTestCompleter], (async) => {
|
|
|
|
var outlet = makeDummyOutlet();
|
|
|
|
|
2015-08-31 00:25:46 -04:00
|
|
|
router.registerPrimaryOutlet(outlet)
|
2015-09-09 00:41:56 -04:00
|
|
|
.then((_) => router.navigateByUrl('/a'))
|
2015-06-03 16:42:57 -04:00
|
|
|
.then((_) => {
|
2015-08-31 00:25:46 -04:00
|
|
|
expect(outlet.spy('activate')).not.toHaveBeenCalled();
|
2015-07-13 19:12:48 -04:00
|
|
|
return router.config([new Route({path: '/a', component: DummyComponent})]);
|
2015-06-03 16:42:57 -04:00
|
|
|
})
|
2015-05-29 17:58:41 -04:00
|
|
|
.then((_) => {
|
2015-08-31 00:25:46 -04:00
|
|
|
expect(outlet.spy('activate')).toHaveBeenCalled();
|
2015-05-29 17:58:41 -04:00
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
}));
|
2015-07-06 20:41:15 -04:00
|
|
|
|
|
|
|
it('should throw when linkParams does not include a route name', () => {
|
|
|
|
expect(() => router.generate(['./']))
|
|
|
|
.toThrowError(`Link "${ListWrapper.toJSON(['./'])}" must include a route name.`);
|
|
|
|
expect(() => router.generate(['/']))
|
|
|
|
.toThrowError(`Link "${ListWrapper.toJSON(['/'])}" must include a route name.`);
|
|
|
|
});
|
|
|
|
|
2015-08-18 14:30:32 -04:00
|
|
|
it('should, when subscribed to, return a disposable subscription', () => {
|
|
|
|
expect(() => {
|
|
|
|
var subscription = router.subscribe((_) => {});
|
|
|
|
ObservableWrapper.dispose(subscription);
|
|
|
|
}).not.toThrow();
|
|
|
|
});
|
2015-07-06 20:41:15 -04:00
|
|
|
|
|
|
|
it('should generate URLs from the root component when the path starts with /', () => {
|
2015-10-25 05:30:27 -04:00
|
|
|
router.config(
|
|
|
|
[new Route({path: '/first/...', component: DummyParentComp, name: 'FirstCmp'})]);
|
2015-07-06 20:41:15 -04:00
|
|
|
|
2015-09-14 20:36:32 -04:00
|
|
|
var instruction = router.generate(['/FirstCmp', 'SecondCmp']);
|
2015-07-17 16:36:53 -04:00
|
|
|
expect(stringifyInstruction(instruction)).toEqual('first/second');
|
|
|
|
|
2015-09-14 20:36:32 -04:00
|
|
|
instruction = router.generate(['/FirstCmp/SecondCmp']);
|
2015-07-17 16:36:53 -04:00
|
|
|
expect(stringifyInstruction(instruction)).toEqual('first/second');
|
2015-07-06 20:41:15 -04:00
|
|
|
});
|
2015-07-08 13:57:38 -04:00
|
|
|
|
2015-08-14 15:31:56 -04:00
|
|
|
it('should generate an instruction with terminal async routes',
|
|
|
|
inject([AsyncTestCompleter], (async) => {
|
|
|
|
var outlet = makeDummyOutlet();
|
|
|
|
|
2015-08-31 00:25:46 -04:00
|
|
|
router.registerPrimaryOutlet(outlet);
|
2015-10-25 05:30:27 -04:00
|
|
|
router.config([new AsyncRoute({path: '/first', loader: loader, name: 'FirstCmp'})]);
|
2015-08-14 15:31:56 -04:00
|
|
|
|
|
|
|
var instruction = router.generate(['/FirstCmp']);
|
2015-09-09 00:41:56 -04:00
|
|
|
router.navigateByInstruction(instruction)
|
2015-08-14 15:31:56 -04:00
|
|
|
.then((_) => {
|
2015-08-31 00:25:46 -04:00
|
|
|
expect(outlet.spy('activate')).toHaveBeenCalled();
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
it('should return whether a given instruction is active with isRouteActive',
|
|
|
|
inject([AsyncTestCompleter], (async) => {
|
|
|
|
var outlet = makeDummyOutlet();
|
|
|
|
|
|
|
|
router.registerPrimaryOutlet(outlet)
|
|
|
|
.then((_) => router.config([
|
2015-10-25 05:30:27 -04:00
|
|
|
new Route({path: '/a', component: DummyComponent, name: 'A'}),
|
|
|
|
new Route({path: '/b', component: DummyComponent, name: 'B'})
|
2015-08-31 00:25:46 -04:00
|
|
|
]))
|
2015-09-09 00:41:56 -04:00
|
|
|
.then((_) => router.navigateByUrl('/a'))
|
2015-08-31 00:25:46 -04:00
|
|
|
.then((_) => {
|
|
|
|
var instruction = router.generate(['/A']);
|
|
|
|
var otherInstruction = router.generate(['/B']);
|
|
|
|
|
|
|
|
expect(router.isRouteActive(instruction)).toEqual(true);
|
|
|
|
expect(router.isRouteActive(otherInstruction)).toEqual(false);
|
2015-08-14 15:31:56 -04:00
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
2015-07-17 16:36:53 -04:00
|
|
|
describe('query string params', () => {
|
|
|
|
it('should use query string params for the root route', () => {
|
|
|
|
router.config(
|
2015-10-25 05:30:27 -04:00
|
|
|
[new Route({path: '/hi/how/are/you', component: DummyComponent, name: 'GreetingUrl'})]);
|
2015-07-21 04:26:43 -04:00
|
|
|
|
2015-09-14 20:36:32 -04:00
|
|
|
var instruction = router.generate(['/GreetingUrl', {'name': 'brad'}]);
|
2015-07-17 16:36:53 -04:00
|
|
|
var path = stringifyInstruction(instruction);
|
|
|
|
expect(path).toEqual('hi/how/are/you?name=brad');
|
|
|
|
});
|
2015-07-21 04:26:43 -04:00
|
|
|
|
2015-07-17 16:36:53 -04:00
|
|
|
it('should serialize parameters that are not part of the route definition as query string params',
|
2015-07-21 04:26:43 -04:00
|
|
|
() => {
|
2015-10-25 05:30:27 -04:00
|
|
|
router.config([
|
|
|
|
new Route({path: '/one/two/:three', component: DummyComponent, name: 'NumberUrl'})
|
|
|
|
]);
|
2015-07-21 04:26:43 -04:00
|
|
|
|
2015-09-14 20:36:32 -04:00
|
|
|
var instruction = router.generate(['/NumberUrl', {'three': 'three', 'four': 'four'}]);
|
2015-07-17 16:36:53 -04:00
|
|
|
var path = stringifyInstruction(instruction);
|
|
|
|
expect(path).toEqual('one/two/three?four=four');
|
2015-07-21 04:26:43 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-07-08 13:57:38 -04:00
|
|
|
describe('matrix params', () => {
|
2015-07-17 16:36:53 -04:00
|
|
|
it('should generate matrix params for each non-root component', () => {
|
2015-07-13 19:12:48 -04:00
|
|
|
router.config(
|
2015-10-25 05:30:27 -04:00
|
|
|
[new Route({path: '/first/...', component: DummyParentComp, name: 'FirstCmp'})]);
|
2015-07-08 13:57:38 -04:00
|
|
|
|
2015-07-17 16:36:53 -04:00
|
|
|
var instruction =
|
2015-09-14 20:36:32 -04:00
|
|
|
router.generate(['/FirstCmp', {'key': 'value'}, 'SecondCmp', {'project': 'angular'}]);
|
2015-07-17 16:36:53 -04:00
|
|
|
var path = stringifyInstruction(instruction);
|
|
|
|
expect(path).toEqual('first/second;project=angular?key=value');
|
2015-07-08 13:57:38 -04:00
|
|
|
});
|
|
|
|
|
2015-07-17 16:36:53 -04:00
|
|
|
it('should work with named params', () => {
|
|
|
|
router.config(
|
2015-10-25 05:30:27 -04:00
|
|
|
[new Route({path: '/first/:token/...', component: DummyParentComp, name: 'FirstCmp'})]);
|
2015-07-08 13:57:38 -04:00
|
|
|
|
2015-07-17 16:36:53 -04:00
|
|
|
var instruction =
|
2015-09-14 20:36:32 -04:00
|
|
|
router.generate(['/FirstCmp', {'token': 'min'}, 'SecondCmp', {'author': 'max'}]);
|
2015-07-17 16:36:53 -04:00
|
|
|
var path = stringifyInstruction(instruction);
|
|
|
|
expect(path).toEqual('first/min/second;author=max');
|
|
|
|
});
|
2015-07-08 13:57:38 -04:00
|
|
|
});
|
2015-05-29 17:58:41 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
{ path: '/foo', redirectTo: '/bar' },
{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
{ path: '/foo', redirectTo: ['Bar'] },
{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
{ path: '/tab', redirectTo: '/tab/users' }
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
2015-11-23 21:07:37 -05:00
|
|
|
|
|
|
|
function stringifyInstruction(instruction): string {
|
|
|
|
return instruction.toRootUrl();
|
|
|
|
}
|
|
|
|
|
2015-08-14 15:31:56 -04:00
|
|
|
function loader(): Promise<Type> {
|
|
|
|
return PromiseWrapper.resolve(DummyComponent);
|
|
|
|
}
|
|
|
|
|
2015-05-21 16:59:14 -04:00
|
|
|
class DummyComponent {}
|
|
|
|
|
2015-10-25 05:30:27 -04:00
|
|
|
@RouteConfig([new Route({path: '/second', component: DummyComponent, name: 'SecondCmp'})])
|
2015-07-06 20:41:15 -04:00
|
|
|
class DummyParentComp {
|
|
|
|
}
|
|
|
|
|
2015-05-29 17:58:41 -04:00
|
|
|
function makeDummyOutlet() {
|
2015-08-26 14:41:41 -04:00
|
|
|
var ref = new SpyRouterOutlet();
|
2015-05-29 17:58:41 -04:00
|
|
|
ref.spy('canActivate').andCallFake((_) => PromiseWrapper.resolve(true));
|
refactor(lifecycle): prefix lifecycle methods with "ng"
BREAKING CHANGE:
Previously, components that would implement lifecycle interfaces would include methods
like "onChanges" or "afterViewInit." Given that components were at risk of using such
names without realizing that Angular would call the methods at different points of
the component lifecycle. This change adds an "ng" prefix to all lifecycle hook methods,
far reducing the risk of an accidental name collision.
To fix, just rename these methods:
* onInit
* onDestroy
* doCheck
* onChanges
* afterContentInit
* afterContentChecked
* afterViewInit
* afterViewChecked
* _Router Hooks_
* onActivate
* onReuse
* onDeactivate
* canReuse
* canDeactivate
To:
* ngOnInit,
* ngOnDestroy,
* ngDoCheck,
* ngOnChanges,
* ngAfterContentInit,
* ngAfterContentChecked,
* ngAfterViewInit,
* ngAfterViewChecked
* _Router Hooks_
* routerOnActivate
* routerOnReuse
* routerOnDeactivate
* routerCanReuse
* routerCanDeactivate
The names of lifecycle interfaces and enums have not changed, though interfaces
have been updated to reflect the new method names.
Closes #5036
2015-11-16 20:04:36 -05:00
|
|
|
ref.spy('routerCanReuse').andCallFake((_) => PromiseWrapper.resolve(false));
|
|
|
|
ref.spy('routerCanDeactivate').andCallFake((_) => PromiseWrapper.resolve(true));
|
2015-08-31 00:25:46 -04:00
|
|
|
ref.spy('activate').andCallFake((_) => PromiseWrapper.resolve(true));
|
2015-05-29 17:58:41 -04:00
|
|
|
return ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
class AppCmp {}
|