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.

Nested transclude issue 2 #8914

Open
Open

Description

@IgorMinar

(reposting from (comment)[https://github.com//pull/7387#issuecomment-54363122])
JSFiddle example here – in the second test, the nested transclude is ignored.

It seems to lose the transcluded content when the ng-transclude is applied to the same element as the nested directive within the outer directive's template.

It works if the ng-transclude is applied to a wrapper element inside the nested directive (but then you're left with an irritating wrapper element).

Activity

  1. added this to the 1.3.0-rc.2 milestone on Sep 3, 2014
  2. IgorMinar commented on Sep 3, 2014

    @IgorMinar
    ContributorAuthor

    @vojtajina could you take a look at this one please?

  3. added a commit that references this issue on Sep 4, 2014
    880eeeb
  4. added 4 commits that reference this issue on Sep 4, 2014
    472162d
    466320f
    930b013
    9d9cdfb
  5. tbosch commented on Sep 15, 2014

    @tbosch
    Contributor

    Reopening as the commit was reverted.

  6. reopened this on Sep 15, 2014
  7. 5 remaining items

  8. modified the milestones: 1.3.0-rc.3, 1.3.0-rc.2 on Sep 15, 2014
  9. modified the milestones: 1.3.0-rc.3, on Sep 22, 2014
  10. fenduru commented on Feb 5, 2015

    @fenduru

    👍 ran into this today

  11. teropa commented on Jun 12, 2015

    @teropa
    Contributor

    I think there's a conceptual mismatch between how the fiddle assumes transclusion to work and how it actually works.

    In short, transclusion determines the content that will be transcluded during compilation, whereas the transclusion itself is actually done during linking. Whether it’s done with ng-transclude or by calling the bound transclusion function some other way, doesn’t really matter.

    So with these directives:

    app.directive('inner', function() {
        return {
            transclude: true,
            template: '<u ng-transclude></u>'
        };
    });
    
    app.directive('outer', function() {
        return {
            transclude: true,
            template: '<a href="#"><inner ng-transclude></inner></a>'
        };
    });
    
    app.directive('workaround', function() {
        return {
            transclude: true,
            template: '<a href="#"><inner><foo ng-transclude></foo></inner></a>'
        };
    });

    The fiddle’s assumption seems to be that this would happen with the when applied to <outer>✔</outer>:

    1. Outer’s content "✔" is stored for later transclusion

    2. Outer’s content is replaced with its template.

       <outer><a href="#"><inner ng-transclude></inner></a></outer>
      
    3. Inner’s content is replaced with "✔" from outer’s transclusion in step 1

      <outer><a href="#"><inner ng-transclude>✔</inner></a></outer>
      
    4. Inner’s content, now "✔" is stored for later transclusion

    5. Inner’s content is replaced with its template.

      <outer><a href="#"><inner ng-transclude><u ng-transclude></u></inner></a></outer>
      
    6. u’s content is replaced with "✔" from the inner transclusion in step 4

      <outer><a href="#"><inner ng-transclude><u ng-transclude>✔</u></inner></a></outer>
      

    However, what actually happens is:

    At compilation time:

    1. Outer’s content "✔" is stored for later transclusion

    2. Outer’s content is replaced with the template.

      <outer><a href="#"><inner ng-transclude></inner></a></outer>
      
    3. Inner’s content, "" is stored for later transclusion

    4. Inner’s content is replaced with its template

      <outer><a href="#"><inner ng-transclude><u ng-transclude></u></inner></a></outer>
      

    At linking time

    1. The ng-transclude on inner is applied. It is "" from step 3.

      <outer><a href="#"><inner ng-transclude></inner></a></outer>
      

    The ng-transclude on u is never done because the element is removed before that.

    For the “workaround” case in the fiddle the mental model holds, because transclude: true and ng-transclude are never used on the same element, which is where the confusion begins.

    There’s probably a way to fix this. To me it seems like it would mean a way for $compile to know not only where transclude: true is enabled, but also where transclusion is actually being applied. I don’t see away to do this without adding complexity and I feel like added complexity is the last thing $compile needs. :)

  12. fenduru commented on Jun 12, 2015

    @fenduru

    @teropa thanks for the break down of why this is happening. However, while the jsbin's mental model might not match the current implementation, it does match the expectation of what the correct behavior would be -- this is kind of the definition of a "bug".

    If you have a directive like outer with this template:

    <a href="#"><inner ng-transclude></inner></a>
    1. It will work fine if <inner> does not use transclusion
    2. It will be broken if <inner> uses transclusion

    This forces <outer> to have intimate implementation knowledge of <inner>, which is unreasonable. <inner> should be able to refactor their code to use transclude without breaking <outer>.

  13. teropa commented on Jun 12, 2015

    @teropa
    Contributor

    @fenduru Agreed, this is a leaky abstraction at the moment.

  14. petebacondarwin commented on Jul 30, 2015

    @petebacondarwin
    Contributor

    @teropa - do you have any ideas of how to fix this? I have no capacity and this is a fairly uncommon corner case. Assigning to the Ice Box for now.

  15. removed their assignment
    on Jul 30, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions