Skip to content
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
@ProLoser

Description

@ProLoser
Contributor

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

rodyhaddad commented on Jul 27, 2013

@rodyhaddad
Contributor

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 no replace: true, the compiler will try to inject the template into the element using .innerHTML, but since doing aCommentNode.innerHTML = someHTML doesn't do anything really, nothing happens.

I wonder if some browsers complain when we try and set the innerHTML on aCommentNode. Was this tested?

Maybe a better behavior would be to throw an error when you have transclude: 'element' combined with a template or templateUrl but no replace: 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

pocesar commented on Apr 14, 2014

@pocesar
Contributor

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 error

caitp

caitp commented on Apr 14, 2014

@caitp
Contributor

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

rodyhaddad commented on Apr 14, 2014

@rodyhaddad
Contributor

@caitp something like http://plnkr.co/edit/M4HKmtU4IL5By7Sv3QQH?p=preview ?

I think for some users of angular, the difference between transclude: 'element' and transclude: true is minor/doesn't exist, design-wise.

caitp

caitp commented on Apr 14, 2014

@caitp
Contributor

@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

pocesar commented on Apr 14, 2014

@pocesar
Contributor

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 chose

caitp

caitp commented on Apr 14, 2014

@caitp
Contributor

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

partap commented on Apr 14, 2014

@partap
Contributor

@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

pocesar commented on Apr 14, 2014

@pocesar
Contributor

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 use transclude:'element' along with other core directives (ng-repeat, ng-transclude, ng-include, etc)

caitp

caitp commented on Apr 14, 2014

@caitp
Contributor

transclude: true is useful if: You have a template, and you want to also include child nodes from the application template. For instance:

<my-component>
  <p>Transclude me into the my-component template</p>
  <p>Also transclude me</p>
</my-component>

This might turn into something like:

<div class="my-component">
  <div class="section">
    <h1>Comments:</h1>
    <p>Transclude me into the my-component template</p>
    <p>Also transclude me</p>
  </div>
  <div class="section">
    <!-- other material ... -->
  </div>
</div>

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:

<p ng-if="foo !== '123'">foo is not equal to '123'!</p>

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

btford commented on Apr 14, 2014

@btford
Contributor

@caitp 👏

caitp

caitp commented on Apr 14, 2014

@caitp
Contributor

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

btford commented on Apr 15, 2014

@btford
Contributor

I'm trying to think how we can add this to the docs.

marknutter

marknutter commented on Apr 28, 2014

@marknutter

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

<input ng-model="test" my-directive />

and I have a template like

<div><label>value: {{test}}</label><div ng-transclude></div></div>

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

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @ProLoser@marknutter@anton-107@pocesar@btford

        Issue actions

          transclude: 'element' is useless without replace:true · Issue #3368 · angular/angular.js