This repository was archived by the owner on Apr 12, 2024. It is now read-only.
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
transclude: 'element' is useless without replace:true #3368
Closed
Description
Version without replace:true
: http://plunker.co/edit/RqAszav0khUoAoPIDS7n?p=preview
Version with replace:true
: http://plunker.co/edit/IbobWmG5e9OlgjJmgVKm?p=preview
Note that in the first, you only get a comment tag. Is this deliberate? Perhaps replace:true
should automatically be set? Or maybe an error should be thrown? Are we expected to do the transclusion ourself if we don't have replace turned on?
Activity
rodyhaddad commentedon Jul 27, 2013
This is not really a bug, in the sense that it is the expected behavior.
A comment node gets created for any directive having
transclude: 'element'
and replaces the actual element node in the DOM (this is deliberate, it's the best solution really).If you have a
template
with noreplace: true
, the compiler will try to inject the template into the element using.innerHTML
, but since doingaCommentNode.innerHTML = someHTML
doesn't do anything really, nothing happens.I wonder if some browsers complain when we try and set the
innerHTML
onaCommentNode
. Was this tested?Maybe a better behavior would be to throw an error when you have
transclude: 'element'
combined with atemplate
ortemplateUrl
but noreplace: true
? It would help beginners for sure.And maybe the error wouldn't be thrown if you have
replace: false
, which wouldn't actually do a replace, but would indicate that you are aware of what you're doing.pocesar commentedon Apr 14, 2014
spent some days trying to figure out how to get the templateUrl when doing transclude: 'element' without setting
replace: true
. at least should be explained in the docs, it's somewhat a trial and errorcaitp commentedon Apr 14, 2014
I'm not sure I understand why you want to use element transclusion with a template, that doesn't really make sense to me (you probably don't need to use "element transclusion" at all, for any reason, because the main use-cases for it are things like ng-repeat and ng-if, which are implemented in core... you might want to use it to implement something similar to ng-view, but remember that ng-view itself doesn't use a template!)
rodyhaddad commentedon Apr 14, 2014
@caitp something like http://plnkr.co/edit/M4HKmtU4IL5By7Sv3QQH?p=preview ?
I think for some users of angular, the difference between
transclude: 'element'
andtransclude: true
is minor/doesn't exist, design-wise.caitp commentedon Apr 14, 2014
@rodyhaddad for a use-case like that, there's no point using
transclude: 'element'
in the first place, because it's essentially just a regular template directive.Element transclusion has a specific use-case, which to me largely involves things which are sort of structural "placeholders" in the DOM, and don't have templates for this reason.
I can't think of a good reason to use
transclude: 'element'
with a template, it simply doesn't make any sense.pocesar commentedon Apr 14, 2014
I use it mainly with
ng-include
to reuse the same controller without having to set<div ng-controller="NCtrl as ctrl">
every single time, plus I use an isolate scope, since transclusion uses the "not imediate parent" scope, I need to transclude it to the scope I chosecaitp commentedon Apr 14, 2014
This doesn't strike me as a compelling reason to use element transclusion, it sounds more like not really assessing the alternatives. Element transclusion has a specific use case, and that use case does not include the use of templates. This is based on my own personal observation and understanding of the framework, but I'm fairly confident that this is not what you want to do.
partap commentedon Apr 14, 2014
@caitp Hmm. Could you explain how @rodyhaddad 's example is an invalid use-case for
transclude: element'
?I could see how it might be useful to be able to wrap arbitrary html with an arbitrary template like that. Are you are implying that in this case he should have used
transclude: true
and just wrapped the entire<select>
?If that is the case, what is a good example of when to use
transclude: 'element'
?edit: never mind...I just noticed you mentioned ng-if and ng-repeat earlier....
pocesar commentedon Apr 14, 2014
also discarding part of the included template is perfectly fine, and you can fine grain it using
transclude: 'element'
which I think is a fine use case, plus the ability to reorder the transcluded items along with the template content. If I wanted to have 5 empty nested divs, I wouldn't be willing to usetransclude:'element'
along with other core directives (ng-repeat
,ng-transclude
,ng-include
, etc)caitp commentedon Apr 14, 2014
transclude: true
is useful if: You have a template, and you want to also include child nodes from the application template. For instance:This might turn into something like:
The myComponent directive here might say "okay, put child nodes in a specific part of my template. So
transclude: true
is more about saying "I want to put child-nodes from the calling template into my own template, at an arbitrary place"transclude: 'element'
is different. It's really all about place-holders, like this:This gets translated into:
<!-- ngIf: foo !== '123' -->
And the expression gets evaluated. When the expression is truthy, ngIf appends the original DOM node (the transcluded element, where "element transclusion" comes from) to the parent node of the comment, after the comment itself.
So the comment is acting as a placeholder for the actual node, which gets placed after it.
So based on these two use-cases for different kinds of "transclusion", what is the purpose in giving an "element transclusion" directive a template? What problem is it solving? Why does it need element transclusion, when it's not actually using it?
These are things which don't really make any sense, which is why this issue raises a lot of eyebrows from me. It seems to be nonsense. None of this has anything to do with which scope is used, or what scope is inherited from. It's just weirdness, if you ask me. There are much more applicable ways to solve the problem you're trying to solve.
Again, I'm not really speaking for anyone, this is my personal opinion, but I'm not convinced that there is any legitimate benefit to using element transclusion for the posted examples, they simply don't need it, and aren't using it.
btford commentedon Apr 14, 2014
@caitp 👏
caitp commentedon Apr 14, 2014
It was a very well-written speech, wasn't it.
Anyways Igor said that yeah, element transclusion is mainly used for special "structural" directives (which mainly are in core, although occasionaly you might see them elsewhere like ui-router), and it's kind of bogus to use a template with them.
Maybe it would be helpful to throw an error when you try to do that, to give a hint that it's not really what's supposed to happen. I'm not sure.
But I think we can close this now!
btford commentedon Apr 15, 2014
I'm trying to think how we can add this to the docs.
marknutter commentedon Apr 28, 2014
I have a scenario where I want to transclude the element and use a template as well. Specifically, I want to wrap an input field in a template and I want that input's scope to be preserved, but I don't want to wrap that input in a separate element where the directive is applied. So I have
and I have a template like
And I want to be able to access the input's ngModelCtrl from my directive (which I can) but I want the input field's ng-model to continue referring to the main controller's scope. I can't figure out any other way to do this other than using transclude:'element' and replace:true, but the transcluded element's scope gets messed up in the process.
20 remaining items