Wrong scope used after passing transclude function to $compile #9413
Description
I've run into something unexpected as demonstrated in this plunker. Specifically, I believe that transcluded elements are being linked to the wrong scope after a manual call to $compile that passes a transclude function. If the transclude function is called on its own -- the cloned elements are linked to the proper scope -- if it's passed to $compile
and then the resulting link function is called, the wrong scope is used.
The plunker creates two directives, "lazy-compile" that lazy compiles its contents when a certain "trigger" variable is made truthy. It does this by, during its compilation phase, removing its contents and storing them in the template cache (so there's only ever one copy). Then, it sets up a bind-once watch for the trigger variable. Once the variable is true, the contents are fetched from the cache, cloned, re-appended to the element, and then $compile
is called on them, passing any transclude function, if defined.
The second directive, "uses-transclude", is just a widget that uses transclusion and the lazy compilation directive in its template.
On the main page, when a link is clicked, the lazy compilation is triggered. This works properly in the plunker -- but only because of an ugly hack that you can see in script.js
. The code there has some comments about what's going on. Essentially, if $compile
is called and the transclude function is passed to it, when you run the resulting link function the transcluded elements are linked to the wrong scope. However, if you call the transclude function directly -- the cloned elements are linked to the proper scope. I would expect the same scope to be used in both cases. So, to resolve this problem, the lazy compile directive calls the transclude function itself, saves the scope's parent (prototypical parent, not $parent
) from the cloned elements, and then rewrites the transclude function to ensure this same parent scope is used when the transclude function is called later in $compile
.
The plunker prints out the "wrong scope" and the "right scope" via console.log
once the compilation link is clicked.
Why are the scopes not the same when doing $compile(el, transcludeFn)(scope)
vs. transcludeFn(function(clone) {})
? Shouldn't the proper scope travel along with the transclude function closure and always be used regardless of where the content is inserted?