Skip to content

Commit

Permalink
fix(angular1-router): add support for using the component helper
Browse files Browse the repository at this point in the history
In Angular 1.5 there is a new helper method for creating component directives.
See https://docs.angularjs.org/guide/component for more information about components.

These kind of directives only match the `E` element form and the previously component
router only created HTML that matched directives that matched the `A` attribute form.

This commit changes the `<ng-outlet>` directive so that it generates custom HTML
elements rather divs with custom attributes to trigger the relevant component to
appear in the DOM.

Going forward, Angular 1.5 users are encouraged to create their router components
using the following style:

```
myModule.componnet('component-name', {
  // component definition object
});
```

Closes angular/angular.js#13860
Closes angular#5278

BREAKING CHANGE:

The component router now creates custom element HTML rather than custom attribute
HTML, in order to create a new component. So rather than

```html
<div custom-component></div>
```

it now creates

```html
<custom-component></custom-component>
```

If you defined you router components using the `directive()` helper and
specified the `restrict` properties such that element matching was not allowed,
e.g. `restrict: 'A'` then these components will no longer be instantiated
by the component router and the outlet will be empty.

The fix is to include `E` in the `restrict` property.

`restrict: 'EA'`

Note that this does not affect directives that did not specify the `restrict`
property as the default for this property is already `EA`.
  • Loading branch information
petebacondarwin committed Jan 31, 2016
1 parent b008f54 commit 6fa2143
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 47 deletions.
3 changes: 2 additions & 1 deletion modules/angular1_router/src/ng_outlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ function ngOutletDirective($animate, $q: ng.IQService, $router) {
}

this.controller.$$routeParams = instruction.params;
this.controller.$$template = '<div ' + dashCase(componentName) + '></div>';
this.controller.$$template =
'<' + dashCase(componentName) + '></' + dashCase(componentName) + '>';
this.controller.$$router = this.router.childRouter(instruction.componentType);

let newScope = scope.$new();
Expand Down
87 changes: 62 additions & 25 deletions modules/angular1_router/test/integration/navigation_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,21 @@ describe('navigation', function () {
$router = _$router_;
});

registerComponent('userCmp', {
registerDirective('userCmp', {
template: '<div>hello {{userCmp.$routeParams.name}}</div>'
});
registerComponent('oneCmp', {
registerDirective('oneCmp', {
template: '<div>{{oneCmp.number}}</div>',
controller: function () {this.number = 'one'}
});
registerComponent('twoCmp', {
registerDirective('twoCmp', {
template: '<div>{{twoCmp.number}}</div>',
controller: function () {this.number = 'two'}
});
registerComponent('threeCmp', {
template: '<div>{{$ctrl.number}}</div>',
controller: function () {this.number = 'three'}
});
});

it('should work in a simple case', function () {
Expand All @@ -47,6 +51,21 @@ describe('navigation', function () {
expect(elt.text()).toBe('one');
});


it('should work with components created by the `mod.component()` helper', function () {
compile('<ng-outlet></ng-outlet>');

$router.config([
{ path: '/', component: 'threeCmp' }
]);

$router.navigateByUrl('/');
$rootScope.$digest();

expect(elt.text()).toBe('three');
});


it('should navigate between components with different parameters', function () {
$router.config([
{ path: '/user/:name', component: 'userCmp' }
Expand All @@ -68,7 +87,7 @@ describe('navigation', function () {
function ParentController() {
instanceCount += 1;
}
registerComponent('parentCmp', {
registerDirective('parentCmp', {
template: 'parent { <ng-outlet></ng-outlet> }',
$routeConfig: [
{ path: '/user/:name', component: 'userCmp' }
Expand All @@ -94,7 +113,7 @@ describe('navigation', function () {


it('should work with nested outlets', function () {
registerComponent('childCmp', {
registerDirective('childCmp', {
template: '<div>inner { <div ng-outlet></div> }</div>',
$routeConfig: [
{ path: '/b', component: 'oneCmp' }
Expand All @@ -114,7 +133,7 @@ describe('navigation', function () {


it('should work with recursive nested outlets', function () {
registerComponent('recurCmp', {
registerDirective('recurCmp', {
template: '<div>recur { <div ng-outlet></div> }</div>',
$routeConfig: [
{ path: '/recur', component: 'recurCmp' },
Expand Down Expand Up @@ -163,7 +182,7 @@ describe('navigation', function () {


it('should change location to the canonical route with nested components', inject(function ($location) {
registerComponent('childRouter', {
registerDirective('childRouter', {
template: '<div>inner { <div ng-outlet></div> }</div>',
$routeConfig: [
{ path: '/new-child', component: 'oneCmp', name: 'NewChild'},
Expand Down Expand Up @@ -208,7 +227,7 @@ describe('navigation', function () {

it('should expose a "navigating" property on $router', inject(function ($q) {
var defer;
registerComponent('pendingActivate', {
registerDirective('pendingActivate', {
$canActivate: function () {
defer = $q.defer();
return defer.promise;
Expand All @@ -227,36 +246,54 @@ describe('navigation', function () {
expect($router.navigating).toBe(false);
}));

function registerComponent(name, options) {
var controller = options.controller || function () {};

['$routerOnActivate', '$routerOnDeactivate', '$routerOnReuse', '$routerCanReuse', '$routerCanDeactivate'].forEach(function (hookName) {
if (options[hookName]) {
controller.prototype[hookName] = options[hookName];
}
});

function registerDirective(name, options) {
function factory() {
return {
template: options.template || '',
controllerAs: name,
controller: controller
controller: getController(options)
};
}
applyStaticProperties(factory, options);
$compileProvider.directive(name, factory);
}

if (options.$canActivate) {
factory.$canActivate = options.$canActivate;
}
if (options.$routeConfig) {
factory.$routeConfig = options.$routeConfig;
}
function registerComponent(name, options) {

$compileProvider.directive(name, factory);
var definition = {
template: options.template || '',
controller: getController(options),
}
applyStaticProperties(definition, options);
$compileProvider.component(name, definition);
}

function compile(template) {
elt = $compile('<div>' + template + '</div>')($rootScope);
$rootScope.$digest();
return elt;
}

function getController(options) {
var controller = options.controller || function () {};
[
'$routerOnActivate', '$routerOnDeactivate',
'$routerOnReuse', '$routerCanReuse',
'$routerCanDeactivate'
].forEach(function (hookName) {
if (options[hookName]) {
controller.prototype[hookName] = options[hookName];
}
});
return controller;
}

function applyStaticProperties(target, options) {
['$canActivate', '$routeConfig'].forEach(function(property) {
if (options[property]) {
target[property] = options[property];
}
});
}
});

15 changes: 10 additions & 5 deletions npm-shrinkwrap.clean.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@
"version": "1.0.0"
},
"angular": {
"version": "1.4.8"
"version": "1.5.0-rc.2"
},
"angular-animate": {
"version": "1.4.8"
"version": "1.5.0-rc.2"
},
"angular-mocks": {
"version": "1.4.8"
"version": "1.5.0-rc.2"
},
"ansi": {
"version": "0.3.0"
Expand Down Expand Up @@ -5337,7 +5337,12 @@
"version": "1.0.0"
},
"ts-api-guardian": {
"version": "0.0.2"
"version": "0.0.2",
"dependencies": {
"typescript": {
"version": "1.7.3"
}
}
},
"ts2dart": {
"version": "0.7.19",
Expand Down Expand Up @@ -5823,5 +5828,5 @@
}
},
"name": "angular-srcs",
"version": "2.0.0-beta.1"
"version": "2.0.0-beta.2"
}
36 changes: 23 additions & 13 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@
"zone.js": "0.5.10"
},
"devDependencies": {
"angular": "^1.4.7",
"angular-animate": "^1.4.7",
"angular-mocks": "^1.4.7",
"angular": "^1.5.0-rc.2",
"angular-animate": "^1.5.0-rc.2",
"angular-mocks": "^1.5.0-rc.2",
"base64-js": "^0.0.8",
"bower": "^1.3.12",
"broccoli": "^0.16.9",
Expand Down

0 comments on commit 6fa2143

Please sign in to comment.