X Tutup
Skip to content

Commit d86be24

Browse files
petebacondarwinIgorMinar
authored andcommitted
fix(angular1-router): add support for using the component helper
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#6076 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`.
1 parent a26053d commit d86be24

File tree

5 files changed

+88
-50
lines changed

5 files changed

+88
-50
lines changed

modules/angular1_router/src/ng_outlet.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ function ngOutletDirective($animate, $q: ng.IQService, $router) {
155155
}
156156

157157
this.controller.$$routeParams = instruction.params;
158-
this.controller.$$template = '<div ' + dashCase(componentName) + '></div>';
158+
this.controller.$$template =
159+
'<' + dashCase(componentName) + '></' + dashCase(componentName) + '>';
159160
this.controller.$$router = this.router.childRouter(instruction.componentType);
160161

161162
let newScope = scope.$new();

modules/angular1_router/test/integration/navigation_spec.js

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,21 @@ describe('navigation', function () {
2121
$router = _$router_;
2222
});
2323

24-
registerComponent('userCmp', {
24+
registerDirective('userCmp', {
2525
template: '<div>hello {{userCmp.$routeParams.name}}</div>'
2626
});
27-
registerComponent('oneCmp', {
27+
registerDirective('oneCmp', {
2828
template: '<div>{{oneCmp.number}}</div>',
2929
controller: function () {this.number = 'one'}
3030
});
31-
registerComponent('twoCmp', {
31+
registerDirective('twoCmp', {
3232
template: '<div>{{twoCmp.number}}</div>',
3333
controller: function () {this.number = 'two'}
3434
});
35+
registerComponent('threeCmp', {
36+
template: '<div>{{$ctrl.number}}</div>',
37+
controller: function () {this.number = 'three'}
38+
});
3539
});
3640

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

54+
55+
it('should work with components created by the `mod.component()` helper', function () {
56+
compile('<ng-outlet></ng-outlet>');
57+
58+
$router.config([
59+
{ path: '/', component: 'threeCmp' }
60+
]);
61+
62+
$router.navigateByUrl('/');
63+
$rootScope.$digest();
64+
65+
expect(elt.text()).toBe('three');
66+
});
67+
68+
5069
it('should navigate between components with different parameters', function () {
5170
$router.config([
5271
{ path: '/user/:name', component: 'userCmp' }
@@ -68,7 +87,7 @@ describe('navigation', function () {
6887
function ParentController() {
6988
instanceCount += 1;
7089
}
71-
registerComponent('parentCmp', {
90+
registerDirective('parentCmp', {
7291
template: 'parent { <ng-outlet></ng-outlet> }',
7392
$routeConfig: [
7493
{ path: '/user/:name', component: 'userCmp' }
@@ -94,7 +113,7 @@ describe('navigation', function () {
94113

95114

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

115134

116135
it('should work with recursive nested outlets', function () {
117-
registerComponent('recurCmp', {
136+
registerDirective('recurCmp', {
118137
template: '<div>recur { <div ng-outlet></div> }</div>',
119138
$routeConfig: [
120139
{ path: '/recur', component: 'recurCmp' },
@@ -163,7 +182,7 @@ describe('navigation', function () {
163182

164183

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

209228
it('should expose a "navigating" property on $router', inject(function ($q) {
210229
var defer;
211-
registerComponent('pendingActivate', {
230+
registerDirective('pendingActivate', {
212231
$canActivate: function () {
213232
defer = $q.defer();
214233
return defer.promise;
@@ -227,36 +246,54 @@ describe('navigation', function () {
227246
expect($router.navigating).toBe(false);
228247
}));
229248

230-
function registerComponent(name, options) {
231-
var controller = options.controller || function () {};
232-
233-
['$routerOnActivate', '$routerOnDeactivate', '$routerOnReuse', '$routerCanReuse', '$routerCanDeactivate'].forEach(function (hookName) {
234-
if (options[hookName]) {
235-
controller.prototype[hookName] = options[hookName];
236-
}
237-
});
238-
249+
function registerDirective(name, options) {
239250
function factory() {
240251
return {
241252
template: options.template || '',
242253
controllerAs: name,
243-
controller: controller
254+
controller: getController(options)
244255
};
245256
}
257+
applyStaticProperties(factory, options);
258+
$compileProvider.directive(name, factory);
259+
}
246260

247-
if (options.$canActivate) {
248-
factory.$canActivate = options.$canActivate;
249-
}
250-
if (options.$routeConfig) {
251-
factory.$routeConfig = options.$routeConfig;
252-
}
261+
function registerComponent(name, options) {
253262

254-
$compileProvider.directive(name, factory);
263+
var definition = {
264+
template: options.template || '',
265+
controller: getController(options),
266+
}
267+
applyStaticProperties(definition, options);
268+
$compileProvider.component(name, definition);
255269
}
256270

257271
function compile(template) {
258272
elt = $compile('<div>' + template + '</div>')($rootScope);
259273
$rootScope.$digest();
260274
return elt;
261275
}
276+
277+
function getController(options) {
278+
var controller = options.controller || function () {};
279+
[
280+
'$routerOnActivate', '$routerOnDeactivate',
281+
'$routerOnReuse', '$routerCanReuse',
282+
'$routerCanDeactivate'
283+
].forEach(function (hookName) {
284+
if (options[hookName]) {
285+
controller.prototype[hookName] = options[hookName];
286+
}
287+
});
288+
return controller;
289+
}
290+
291+
function applyStaticProperties(target, options) {
292+
['$canActivate', '$routeConfig'].forEach(function(property) {
293+
if (options[property]) {
294+
target[property] = options[property];
295+
}
296+
});
297+
}
262298
});
299+

npm-shrinkwrap.clean.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,13 @@
4646
"version": "1.0.0"
4747
},
4848
"angular": {
49-
"version": "1.4.8"
49+
"version": "1.5.0"
5050
},
5151
"angular-animate": {
52-
"version": "1.4.8"
52+
"version": "1.5.0"
5353
},
5454
"angular-mocks": {
55-
"version": "1.4.8"
55+
"version": "1.5.0"
5656
},
5757
"ansi": {
5858
"version": "0.3.0"
@@ -5828,5 +5828,5 @@
58285828
}
58295829
},
58305830
"name": "angular-srcs",
5831-
"version": "2.0.0-beta.2"
5831+
"version": "2.0.0-beta.3"
58325832
}

npm-shrinkwrap.json

Lines changed: 17 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@
3939
"zone.js": "0.5.13"
4040
},
4141
"devDependencies": {
42-
"angular": "^1.4.7",
43-
"angular-animate": "^1.4.7",
44-
"angular-mocks": "^1.4.7",
42+
"angular": "^1.5.0",
43+
"angular-animate": "^1.5.0",
44+
"angular-mocks": "^1.5.0",
4545
"base64-js": "^0.0.8",
4646
"bower": "^1.3.12",
4747
"broccoli": "^0.16.9",

0 commit comments

Comments
 (0)
X Tutup