2015-08-20 17:26:57 -04:00
|
|
|
'use strict';
|
|
|
|
|
2015-08-31 18:53:37 -04:00
|
|
|
describe('navigation', function () {
|
2015-08-20 17:26:57 -04:00
|
|
|
|
|
|
|
var elt,
|
|
|
|
$compile,
|
|
|
|
$rootScope,
|
|
|
|
$router,
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
$compileProvider;
|
2015-08-20 17:26:57 -04:00
|
|
|
|
|
|
|
beforeEach(function () {
|
|
|
|
module('ng');
|
|
|
|
module('ngComponentRouter');
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
module(function (_$compileProvider_) {
|
|
|
|
$compileProvider = _$compileProvider_;
|
2015-08-20 17:26:57 -04:00
|
|
|
});
|
|
|
|
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
inject(function (_$compile_, _$rootScope_, _$router_) {
|
2015-08-20 17:26:57 -04:00
|
|
|
$compile = _$compile_;
|
|
|
|
$rootScope = _$rootScope_;
|
|
|
|
$router = _$router_;
|
|
|
|
});
|
|
|
|
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
registerComponent('userCmp', {
|
|
|
|
template: '<div>hello {{userCmp.$routeParams.name}}</div>'
|
|
|
|
});
|
|
|
|
registerComponent('oneCmp', {
|
|
|
|
template: '<div>{{oneCmp.number}}</div>',
|
|
|
|
controller: function () {this.number = 'one'}
|
|
|
|
});
|
|
|
|
registerComponent('twoCmp', {
|
|
|
|
template: '<div>{{twoCmp.number}}</div>',
|
|
|
|
controller: function () {this.number = 'two'}
|
2015-08-20 17:26:57 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should work in a simple case', function () {
|
|
|
|
compile('<ng-outlet></ng-outlet>');
|
|
|
|
|
|
|
|
$router.config([
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
{ path: '/', component: 'oneCmp' }
|
2015-08-20 17:26:57 -04:00
|
|
|
]);
|
|
|
|
|
2015-09-09 00:41:56 -04:00
|
|
|
$router.navigateByUrl('/');
|
2015-08-20 17:26:57 -04:00
|
|
|
$rootScope.$digest();
|
|
|
|
|
|
|
|
expect(elt.text()).toBe('one');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should navigate between components with different parameters', function () {
|
|
|
|
$router.config([
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
{ path: '/user/:name', component: 'userCmp' }
|
2015-08-20 17:26:57 -04:00
|
|
|
]);
|
|
|
|
compile('<ng-outlet></ng-outlet>');
|
|
|
|
|
2015-09-09 00:41:56 -04:00
|
|
|
$router.navigateByUrl('/user/brian');
|
2015-08-20 17:26:57 -04:00
|
|
|
$rootScope.$digest();
|
|
|
|
expect(elt.text()).toBe('hello brian');
|
|
|
|
|
2015-09-09 00:41:56 -04:00
|
|
|
$router.navigateByUrl('/user/igor');
|
2015-08-20 17:26:57 -04:00
|
|
|
$rootScope.$digest();
|
|
|
|
expect(elt.text()).toBe('hello igor');
|
|
|
|
});
|
|
|
|
|
|
|
|
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
it('should reuse a parent when navigating between child components with different parameters', function () {
|
|
|
|
var instanceCount = 0;
|
|
|
|
function ParentController() {
|
|
|
|
instanceCount += 1;
|
|
|
|
}
|
|
|
|
registerComponent('parentCmp', {
|
|
|
|
template: 'parent { <ng-outlet></ng-outlet> }',
|
|
|
|
$routeConfig: [
|
|
|
|
{ path: '/user/:name', component: 'userCmp' }
|
|
|
|
],
|
|
|
|
controller: ParentController
|
|
|
|
});
|
2015-08-20 17:26:57 -04:00
|
|
|
|
|
|
|
$router.config([
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
{ path: '/parent/...', component: 'parentCmp' }
|
2015-08-20 17:26:57 -04:00
|
|
|
]);
|
|
|
|
compile('<ng-outlet></ng-outlet>');
|
|
|
|
|
2015-09-09 00:41:56 -04:00
|
|
|
$router.navigateByUrl('/parent/user/brian');
|
2015-08-20 17:26:57 -04:00
|
|
|
$rootScope.$digest();
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
expect(instanceCount).toBe(1);
|
2015-08-20 17:26:57 -04:00
|
|
|
expect(elt.text()).toBe('parent { hello brian }');
|
|
|
|
|
2015-09-09 00:41:56 -04:00
|
|
|
$router.navigateByUrl('/parent/user/igor');
|
2015-08-20 17:26:57 -04:00
|
|
|
$rootScope.$digest();
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
expect(instanceCount).toBe(1);
|
2015-08-20 17:26:57 -04:00
|
|
|
expect(elt.text()).toBe('parent { hello igor }');
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('should work with nested outlets', function () {
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
registerComponent('childCmp', {
|
|
|
|
template: '<div>inner { <div ng-outlet></div> }</div>',
|
|
|
|
$routeConfig: [
|
|
|
|
{ path: '/b', component: 'oneCmp' }
|
|
|
|
]
|
|
|
|
});
|
2015-08-20 17:26:57 -04:00
|
|
|
|
|
|
|
$router.config([
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
{ path: '/a/...', component: 'childCmp' }
|
2015-08-20 17:26:57 -04:00
|
|
|
]);
|
|
|
|
compile('<div>outer { <div ng-outlet></div> }</div>');
|
|
|
|
|
2015-09-09 00:41:56 -04:00
|
|
|
$router.navigateByUrl('/a/b');
|
2015-08-20 17:26:57 -04:00
|
|
|
$rootScope.$digest();
|
|
|
|
|
|
|
|
expect(elt.text()).toBe('outer { inner { one } }');
|
|
|
|
});
|
|
|
|
|
|
|
|
|
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
|
|
|
it('should work with recursive nested outlets', function () {
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
registerComponent('recurCmp', {
|
|
|
|
template: '<div>recur { <div ng-outlet></div> }</div>',
|
|
|
|
$routeConfig: [
|
|
|
|
{ path: '/recur', component: 'recurCmp' },
|
|
|
|
{ path: '/end', component: 'oneCmp' }
|
|
|
|
]});
|
|
|
|
|
2015-08-20 17:26:57 -04:00
|
|
|
$router.config([
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
{ path: '/recur', component: 'recurCmp' },
|
|
|
|
{ path: '/', component: 'oneCmp' }
|
2015-08-20 17:26:57 -04:00
|
|
|
]);
|
|
|
|
|
|
|
|
compile('<div>root { <div ng-outlet></div> }</div>');
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
$router.navigateByUrl('/recur/recur/end');
|
2015-08-20 17:26:57 -04:00
|
|
|
$rootScope.$digest();
|
|
|
|
expect(elt.text()).toBe('root { one }');
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('should change location path', inject(function ($location) {
|
|
|
|
$router.config([
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
{ path: '/user', component: 'userCmp' }
|
2015-08-20 17:26:57 -04:00
|
|
|
]);
|
|
|
|
|
|
|
|
compile('<div ng-outlet></div>');
|
|
|
|
|
2015-09-09 00:41:56 -04:00
|
|
|
$router.navigateByUrl('/user');
|
2015-08-20 17:26:57 -04:00
|
|
|
$rootScope.$digest();
|
|
|
|
|
|
|
|
expect($location.path()).toBe('/user');
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
it('should change location to the canonical route', inject(function ($location) {
|
|
|
|
compile('<div ng-outlet></div>');
|
|
|
|
|
|
|
|
$router.config([
|
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
|
|
|
{ path: '/', redirectTo: ['/User'] },
|
|
|
|
{ path: '/user', component: 'userCmp', name: 'User' }
|
2015-08-20 17:26:57 -04:00
|
|
|
]);
|
|
|
|
|
2015-09-09 00:41:56 -04:00
|
|
|
$router.navigateByUrl('/');
|
2015-08-20 17:26:57 -04:00
|
|
|
$rootScope.$digest();
|
|
|
|
|
|
|
|
expect($location.path()).toBe('/user');
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
it('should change location to the canonical route with nested components', inject(function ($location) {
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
registerComponent('childRouter', {
|
|
|
|
template: '<div>inner { <div ng-outlet></div> }</div>',
|
|
|
|
$routeConfig: [
|
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
|
|
|
{ path: '/new-child', component: 'oneCmp', name: 'NewChild'},
|
|
|
|
{ path: '/new-child-two', component: 'twoCmp', name: 'NewChildTwo'}
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
]
|
|
|
|
});
|
2015-08-20 17:26:57 -04:00
|
|
|
|
|
|
|
$router.config([
|
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
|
|
|
{ path: '/old-parent/old-child', redirectTo: ['/NewParent', 'NewChild'] },
|
|
|
|
{ path: '/old-parent/old-child-two', redirectTo: ['/NewParent', 'NewChildTwo'] },
|
|
|
|
{ path: '/new-parent/...', component: 'childRouter', name: 'NewParent' }
|
2015-08-20 17:26:57 -04:00
|
|
|
]);
|
|
|
|
|
|
|
|
compile('<div ng-outlet></div>');
|
|
|
|
|
2015-09-09 00:41:56 -04:00
|
|
|
$router.navigateByUrl('/old-parent/old-child');
|
2015-08-20 17:26:57 -04:00
|
|
|
$rootScope.$digest();
|
|
|
|
|
|
|
|
expect($location.path()).toBe('/new-parent/new-child');
|
|
|
|
expect(elt.text()).toBe('inner { one }');
|
|
|
|
|
2015-09-09 00:41:56 -04:00
|
|
|
$router.navigateByUrl('/old-parent/old-child-two');
|
2015-08-20 17:26:57 -04:00
|
|
|
$rootScope.$digest();
|
|
|
|
|
|
|
|
expect($location.path()).toBe('/new-parent/new-child-two');
|
|
|
|
expect(elt.text()).toBe('inner { two }');
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
it('should navigate when the location path changes', inject(function ($location) {
|
|
|
|
$router.config([
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
{ path: '/one', component: 'oneCmp' }
|
2015-08-20 17:26:57 -04:00
|
|
|
]);
|
|
|
|
compile('<div ng-outlet></div>');
|
|
|
|
|
|
|
|
$location.path('/one');
|
|
|
|
$rootScope.$digest();
|
|
|
|
|
|
|
|
expect(elt.text()).toBe('one');
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
it('should expose a "navigating" property on $router', inject(function ($q) {
|
|
|
|
var defer;
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
registerComponent('pendingActivate', {
|
|
|
|
$canActivate: function () {
|
2015-08-20 17:26:57 -04:00
|
|
|
defer = $q.defer();
|
|
|
|
return defer.promise;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
$router.config([
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
{ path: '/pending-activate', component: 'pendingActivate' }
|
2015-08-20 17:26:57 -04:00
|
|
|
]);
|
|
|
|
compile('<div ng-outlet></div>');
|
|
|
|
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
$router.navigateByUrl('/pending-activate');
|
2015-08-20 17:26:57 -04:00
|
|
|
$rootScope.$digest();
|
|
|
|
expect($router.navigating).toBe(true);
|
|
|
|
defer.resolve();
|
|
|
|
$rootScope.$digest();
|
|
|
|
expect($router.navigating).toBe(false);
|
|
|
|
}));
|
|
|
|
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
function registerComponent(name, options) {
|
|
|
|
var controller = options.controller || function () {};
|
2015-08-20 17:26:57 -04:00
|
|
|
|
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
|
|
|
['$routerOnActivate', '$routerOnDeactivate', '$routerOnReuse', '$routerCanReuse', '$routerCanDeactivate'].forEach(function (hookName) {
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
if (options[hookName]) {
|
|
|
|
controller.prototype[hookName] = options[hookName];
|
2015-08-20 17:26:57 -04:00
|
|
|
}
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
function factory() {
|
|
|
|
return {
|
|
|
|
template: options.template || '',
|
|
|
|
controllerAs: name,
|
|
|
|
controller: controller
|
|
|
|
};
|
2015-08-20 17:26:57 -04:00
|
|
|
}
|
|
|
|
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
if (options.$canActivate) {
|
|
|
|
factory.$canActivate = options.$canActivate;
|
|
|
|
}
|
|
|
|
if (options.$routeConfig) {
|
|
|
|
factory.$routeConfig = options.$routeConfig;
|
|
|
|
}
|
2015-08-20 17:26:57 -04:00
|
|
|
|
refactor(angular_1_router): use directives for route targets
BREAKING CHANGE:
Previously, route configuration took a controller constructor function as the value of
`component` in a route definition:
```
$route.config([
{ route: '/', component: MyController }
])
```
Based on the name of the controller, we used to use a componentMapper service to
determine what template to pair with each controller, how to bind the instance to
the $scope.
To make the 1.x router more semantically alligned with Angular 2, we now route to a directive.
Thus a route configuration takes a normalized directive name:
```
$route.config([
{ route: '/', component: 'myDirective' }
])
```
BREAKING CHANGE:
In order to avoid name collisions, lifecycle hooks are now prefixed with `$`. Before:
```
MyController.prototype.onActivate = ...
```
After:
```
MyController.prototype.$onActivate = ...
```
Same for `$canActivate` (which now lives on the directive factory function),
`$canDeactivate`, `$canReuse`, and `$onDeactivate` hooks.
2015-09-18 18:53:50 -04:00
|
|
|
$compileProvider.directive(name, factory);
|
2015-08-20 17:26:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
function compile(template) {
|
|
|
|
elt = $compile('<div>' + template + '</div>')($rootScope);
|
|
|
|
$rootScope.$digest();
|
|
|
|
return elt;
|
|
|
|
}
|
|
|
|
});
|