Skip to content

Commit 27833b9

Browse files
committed
fix(asDirectiveSpec): improve specs, improve example, fix non normalized case and do not publish DOMElements into scope
1 parent e2c0036 commit 27833b9

File tree

2 files changed

+67
-101
lines changed

2 files changed

+67
-101
lines changed

src/ng/directive/as.js

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,20 @@
1919
* This example demonstrates basic publishing of the component controller into the scope.
2020
* <example name="asDirectiveComponentExample" module="asComponentExample">
2121
* <file name="index.html">
22-
* <script>
23-
* angular.module('asComponentExample', [])
24-
* .component('toggle', {
25-
* controller: function() {
26-
* var opened = false;
27-
* this.isOpen = function() { return opened; };
28-
* this.toggle = function() { opened = !opened; };
29-
* }
30-
* });
31-
* </script>
3222
* <toggle as="myToggle"></toggle>
3323
* <button ng-click="myToggle.toggle()">Toggle</button>
3424
* <div ng-show="myToggle.isOpen()">You are using a children component to show it.</div>
3525
* </file>
26+
* <file name="script.js">
27+
* angular.module('asComponentExample', [])
28+
* .component('toggle', {
29+
* controller: function() {
30+
* var opened = false;
31+
* this.isOpen = function() { return opened; };
32+
* this.toggle = function() { opened = !opened; };
33+
* }
34+
* });
35+
* </file>
3636
* <file name="protractor.js" type="protractor">
3737
* it('should publish the toggle into the scope', function() {
3838
* var toggle = element(by.buttonText('Toggle'));
@@ -42,34 +42,13 @@
4242
* });
4343
* </file>
4444
* </example>
45-
*
46-
* This directive also allows to bind elements to the scope.
47-
*
48-
* ```js
49-
* var myMod = angular.module(...);
50-
* myMod.component('myPlayer', {
51-
* template: '' +
52-
* '<audio as="$ctrl.audio" src="foo.ogg"></audio>' +
53-
* '<button ng-click="$ctrl.play()">Play</button>' +
54-
* '',
55-
* controller: function() {
56-
* this.play = function() {
57-
* this.audio.play();
58-
* };
59-
* }
60-
* });
61-
* ```
62-
*
63-
* Note that angular does not allows to access DOM elements directly
64-
* from templates, you need a controller to manipulate them.
65-
*
6645
*/
6746
var componentAsDirective = ['$parse', function($parse) {
6847
return {
6948
restrict: 'A',
7049
compile: function(tElement, tAttrs) {
71-
// gets the theoretical controller name, converts <some-thing> into "someThing")
72-
var controllerName = tElement[0].tagName.toLowerCase()
50+
// gets the expected controller name, converts <x-some-thing> into "someThing")
51+
var controllerName = tAttrs.$normalize(tElement[0].tagName.toLowerCase())
7352
.replace(/[^\w]\w/g, function(a) { return a.slice(1).toUpperCase(); });
7453

7554
// get the setter for the as attribute
@@ -78,12 +57,7 @@ var componentAsDirective = ['$parse', function($parse) {
7857
return function(scope, iElement, iAttrs) {
7958
// gets the controller of the current element (see jqLiteController for details)
8059
var controller = iElement.data('$' + controllerName + 'Controller');
81-
82-
if (controller) {
83-
setter(scope, controller);
84-
} else {
85-
setter(scope, iElement[0]);
86-
}
60+
setter(scope, controller);
8761
};
8862
}
8963
};

test/ng/directive/asSpec.js

Lines changed: 54 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,86 +2,78 @@
22

33
describe('as', function() {
44

5-
it('should bind in the current scope the controller of a component', function() {
6-
var expected = {some: 'value'};
7-
8-
angular.module('my', []).component('myComponent', {
9-
template: 'foo',
10-
controller: function() {
11-
this.property = expected;
12-
}
13-
});
14-
module('my');
5+
describe('given a component', function() {
156

16-
inject(function($compile, $rootScope) {
17-
var scope = $rootScope.$new();
7+
var myComponentController, $rootScope, $compile;
8+
9+
beforeEach(module(function($compileProvider) {
10+
$compileProvider.component('myComponent', {
11+
template: 'foo',
12+
controller: function() {
13+
myComponentController = this;
14+
}
15+
});
16+
}));
17+
18+
beforeEach(inject(function(_$compile_, _$rootScope_) {
19+
$rootScope = _$rootScope_;
20+
$compile = _$compile_;
21+
}));
22+
23+
it('should bind in the current scope the controller of a component', function() {
1824
var $ctrl = {undamaged: true};
19-
scope.$ctrl = $ctrl;
20-
dealoc($compile('<my-component as="$ctrl.myComponent"></my-component>')(scope));
21-
22-
expect(scope.$ctrl).toBe($ctrl);
23-
expect(scope.$ctrl.undamaged).toBe(true);
24-
expect($ctrl.myComponent).not.toBeUndefined();
25-
expect($ctrl.myComponent && $ctrl.myComponent.property).toBe(expected);
26-
scope.$destroy();
25+
$rootScope.$ctrl = $ctrl;
26+
27+
$compile('<my-component as="$ctrl.myComponent"></my-component>')($rootScope);
28+
expect($rootScope.$ctrl).toBe($ctrl);
29+
expect($rootScope.$ctrl.undamaged).toBe(true);
30+
expect($ctrl.myComponent).toBe(myComponentController);
2731
});
28-
});
2932

30-
it('should be parametrized with any variable', function() {
31-
var myComponentController;
33+
it('should be parametrized with any variable', function() {
34+
$compile('<my-component as="bar.myComponent"></my-component>')($rootScope);
35+
expect($rootScope.bar.myComponent).toBe(myComponentController);
36+
});
37+
38+
it('should work with non normalized versions of the entity', function() {
39+
$compile('<my:component as="$ctrl.myComponent1"></my:component>')($rootScope);
40+
expect($rootScope.$ctrl.myComponent1).toBe(myComponentController);
3241

33-
angular.module('my', []).component('myComponent', {
34-
template: 'foo',
35-
controller: function() {
36-
myComponentController = this;
37-
}
42+
$compile('<data-my-component as="$ctrl.myComponent2"></data-my-component>')($rootScope);
43+
expect($rootScope.$ctrl.myComponent2).toBe(myComponentController);
44+
45+
$compile('<x-my-component as="$ctrl.myComponent3"></x-my-component>')($rootScope);
46+
expect($rootScope.$ctrl.myComponent3).toBe(myComponentController);
3847
});
39-
module('my');
4048

41-
inject(function($compile, $rootScope) {
42-
var scope = $rootScope.$new();
43-
dealoc($compile('<my-component as="bar.myComponent"></my-component>')(scope));
49+
it('should work with non normalized versions of as attribute', function() {
50+
$compile('<my-component data-as="$ctrl.myComponent1"></my-component>')($rootScope);
51+
expect($rootScope.$ctrl.myComponent1).toBe(myComponentController);
4452

45-
expect(scope.bar).not.toBeUndefined();
46-
expect(scope.bar && scope.bar.myComponent).toBe(myComponentController);
47-
scope.$destroy();
53+
$compile('<my-component x-as="$ctrl.myComponent2"></my-component>')($rootScope);
54+
expect($rootScope.$ctrl.myComponent2).toBe(myComponentController);
4855
});
56+
4957
});
5058

51-
it('should be compatible with entity directives with controller', function() {
59+
it('should be compatible with directives on entities with controller', function() {
5260
var myDirectiveController;
5361

54-
angular.module('my', []).directive('myDirective', function() {
55-
return {
56-
restrict: 'E',
57-
controller: function() {
58-
myDirectiveController = this;
59-
}
60-
};
62+
module(function($compileProvider) {
63+
$compileProvider.directive('myDirective', function() {
64+
return {
65+
controller: function() {
66+
myDirectiveController = this;
67+
}
68+
};
69+
});
6170
});
62-
module('my');
6371

6472
inject(function($compile, $rootScope) {
65-
var scope = $rootScope.$new();
66-
dealoc($compile('<my-directive as="bar.myDirective"></my-directive>')(scope));
73+
$compile('<my-directive as="bar.myDirective"></my-directive>')($rootScope);
6774

68-
expect(scope.bar).not.toBeUndefined();
69-
expect(scope.bar && scope.bar.myDirective).toBe(myDirectiveController);
70-
scope.$destroy();
75+
expect($rootScope.bar.myDirective).toBe(myDirectiveController);
7176
});
7277
});
7378

74-
it('should bind non HTMLElements elements into the current scope if no component', inject(function($compile, $rootScope) {
75-
var scope = $rootScope.$new();
76-
var $ctrl = {};
77-
scope.$ctrl = $ctrl;
78-
var element = $compile('<div as="$ctrl.myDiv">SUCCESS</div>')(scope);
79-
80-
expect(scope.$ctrl).toBe($ctrl);
81-
expect($ctrl.myDiv).not.toBeUndefined();
82-
expect($ctrl.myDiv && $ctrl.myDiv.textContent).toBe('SUCCESS'); // https://jsperf.com/innerhtml-vs-innertext/49
83-
dealoc(element);
84-
scope.$destroy();
85-
}));
86-
8779
});

0 commit comments

Comments
 (0)