aboutsummaryrefslogtreecommitdiffstats
path: root/test/ng
diff options
context:
space:
mode:
authorVojta Jina2013-09-08 10:05:25 -0700
committerIgor Minar2013-09-30 15:30:29 -0700
commit742271ffa3a518d9e8ef2cb97c24b45b44e3378d (patch)
treec9c5567e0b7068d77f5df0b353452b5c8f88a35c /test/ng
parentdf9426dbc6b3bf9268f136e3a61e8291775c24a8 (diff)
downloadangular.js-742271ffa3a518d9e8ef2cb97c24b45b44e3378d.tar.bz2
fix($compile): link parents before traversing
How did compiling a templateUrl (async) directive with `replace:true` work before this commit? 1/ apply all directives with higher priority than the templateUrl directive 2/ partially apply the templateUrl directive (create `beforeTemplateNodeLinkFn`) 3/ fetch the template 4/ apply second part of the templateUrl directive on the fetched template (`afterTemplateNodeLinkFn`) That is, the templateUrl directive is basically split into two parts (two `nodeLinkFn` functions), which has to be both applied. Normally we compose linking functions (`nodeLinkFn`) using continuation - calling the linking function of a parent element, passing the linking function of the child elements as an argument. The parent linking function then does: 1/ execute its pre-link functions 2/ call the child elements linking function (traverse) 3/ execute its post-link functions Now, we have two linking functions for the same DOM element level (because the templateUrl directive has been split). There has been multiple issues because of the order of these two linking functions (creating controller before setting up scope locals, running linking functions before instantiating controller, etc.). It is easy to fix one use case, but it breaks some other use case. It is hard to decide what is the "correct" order of these two linking functions as they are essentially on the same level. Running them side-by-side screws up pre/post linking functions for the high priority directives (those executed before the templateUrl directive). It runs post-linking functions before traversing: ```js beforeTemplateNodeLinkFn(null); // do not travers afterTemplateNodeLinkFn(afterTemplateChildLinkFn); ``` Composing them (in any order) screws up the order of post-linking functions. We could fix this by having post-linking functions to execute in reverse order (from the lowest priority to the highest) which might actually make a sense. **My solution is to remove this splitting.** This commit removes the `beforeTemplateNodeLinkFn`. The first run (before we have the template) only schedules fetching the template. The rest (creating scope locals, instantiating a controller, linking functions, etc) is done when processing the directive again (in the context of the already fetched template; this is the cloned `derivedSyncDirective`). We still need to pass-through the linking functions of the higher priority directives (those executed before the templateUrl directive), that's why I added `preLinkFns` and `postLinkFns` arguments to `applyDirectivesToNode`. This also changes the "$compile transclude should make the result of a transclusion available to the parent directive in post- linking phase (templateUrl)" unit test. It was testing that a parent directive can see the content of transclusion in its pre-link function. That is IMHO wrong (as the `ngTransclude` directive inserts the translusion in its linking function). This test was only passing because of c173ca412878d537b18df01f39e400ea48a4b398, which changed the behavior of the compiler to traverse before executing the parent linking function. That was wrong and also caused the #3792 issue, which this change fixes. Closes #3792 Closes #3923 Closes #3935 Closes #3927
Diffstat (limited to 'test/ng')
-rwxr-xr-xtest/ng/compileSpec.js52
1 files changed, 44 insertions, 8 deletions
diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js
index 2d6485d9..c6ba5480 100755
--- a/test/ng/compileSpec.js
+++ b/test/ng/compileSpec.js
@@ -1046,7 +1046,10 @@ describe('$compile', function() {
priority: priority,
compile: function() {
log(name + '-C');
- return function() { log(name + '-L'); }
+ return {
+ pre: function() { log(name + '-PreL'); },
+ post: function() { log(name + '-PostL'); }
+ }
}
}, options || {}));
});
@@ -1075,7 +1078,8 @@ describe('$compile', function() {
$rootScope.$digest();
expect(log).toEqual(
'first-C; FLUSH; second-C; last-C; third-C; ' +
- 'third-L; first-L; second-L; last-L');
+ 'first-PreL; second-PreL; last-PreL; third-PreL; ' +
+ 'third-PostL; first-PostL; second-PostL; last-PostL');
var span = element.find('span');
expect(span.attr('first')).toEqual('');
@@ -1099,7 +1103,8 @@ describe('$compile', function() {
$rootScope.$digest();
expect(log).toEqual(
'iFirst-C; FLUSH; iSecond-C; iThird-C; iLast-C; ' +
- 'iFirst-L; iSecond-L; iThird-L; iLast-L');
+ 'iFirst-PreL; iSecond-PreL; iThird-PreL; iLast-PreL; ' +
+ 'iFirst-PostL; iSecond-PostL; iThird-PostL; iLast-PostL');
var div = element.find('div');
expect(div.attr('i-first')).toEqual('');
@@ -1124,7 +1129,8 @@ describe('$compile', function() {
$rootScope.$digest();
expect(log).toEqual(
'first-C; FLUSH; second-C; last-C; third-C; ' +
- 'third-L; first-L; second-L; last-L');
+ 'first-PreL; second-PreL; last-PreL; third-PreL; ' +
+ 'third-PostL; first-PostL; second-PostL; last-PostL');
var span = element.find('span');
expect(span.attr('first')).toEqual('');
@@ -1149,7 +1155,8 @@ describe('$compile', function() {
$rootScope.$digest();
expect(log).toEqual(
'iFirst-C; FLUSH; iSecond-C; iThird-C; iLast-C; ' +
- 'iFirst-L; iSecond-L; iThird-L; iLast-L');
+ 'iFirst-PreL; iSecond-PreL; iThird-PreL; iLast-PreL; ' +
+ 'iFirst-PostL; iSecond-PostL; iThird-PostL; iLast-PostL');
var div = element.find('div');
expect(div.attr('i-first')).toEqual('');
@@ -1264,6 +1271,35 @@ describe('$compile', function() {
expect(element.text()).toBe('boom!1|boom!2|');
});
});
+
+
+ it('should support templateUrl with replace', function() {
+ // a regression https://github.com/angular/angular.js/issues/3792
+ module(function($compileProvider) {
+ $compileProvider.directive('simple', function() {
+ return {
+ templateUrl: '/some.html',
+ replace: true
+ };
+ });
+ });
+
+ inject(function($templateCache, $rootScope, $compile) {
+ $templateCache.put('/some.html',
+ '<div ng-switch="i">' +
+ '<div ng-switch-when="1">i = 1</div>' +
+ '<div ng-switch-default>I dont know what `i` is.</div>' +
+ '</div>');
+
+ element = $compile('<div simple></div>')($rootScope);
+
+ $rootScope.$apply(function() {
+ $rootScope.i = 1;
+ });
+
+ expect(element.html()).toContain('i = 1');
+ });
+ });
});
@@ -1482,7 +1518,7 @@ describe('$compile', function() {
function($rootScope, $compile) {
expect(function(){
$compile('<div class="iscope-a; scope-b"></div>');
- }).toThrowMinErr('$compile', 'multidir', 'Multiple directives [iscopeA, scopeB] asking for isolated scope on: ' +
+ }).toThrowMinErr('$compile', 'multidir', 'Multiple directives [iscopeA, scopeB] asking for new/isolated scope on: ' +
'<div class="iscope-a; scope-b ng-isolate-scope ng-scope">');
})
);
@@ -2824,7 +2860,7 @@ describe('$compile', function() {
});
- it('should make the result of a transclusion available to the parent directive in pre- and post- linking phase (templateUrl)',
+ it('should make the result of a transclusion available to the parent directive in post-linking phase (templateUrl)',
function() {
// when compiling an async directive the transclusion is always processed before the directive
// this is different compared to sync directive. delaying the transclusion makes little sense.
@@ -2850,7 +2886,7 @@ describe('$compile', function() {
element = $compile('<div trans><span>unicorn!</span></div>')($rootScope);
$rootScope.$apply();
- expect(log).toEqual('pre(unicorn!); post(unicorn!)');
+ expect(log).toEqual('pre(); post(unicorn!)');
});
});
});