Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

cloneLinkingFn sometimes gets an empty clone with multiple slots #16607

Closed
1 of 3 tasks
Sennahoi opened this issue Jun 21, 2018 · 11 comments
Closed
1 of 3 tasks

cloneLinkingFn sometimes gets an empty clone with multiple slots #16607

Sennahoi opened this issue Jun 21, 2018 · 11 comments

Comments

@Sennahoi
Copy link

I'm submitting a ...

  • bug report
  • feature request
  • other

Current behavior:
Since AngularJS 1.7.1 we sometimes see the following behavior in Firefox (Windows, Mac, Release and Nightly), but not in Chrome.

HTML:
<some-component>
  <slota>
  .. Tags and text
  </slota>
  <slotb>
  .. Tags and text
  </slotb>
</some-component>

Component someComponent:
 transclude: {
    'slota': 'slota',
    'slotb': '?slotb'
 },

 and in the template:
 <li  ng-repeat="item in items"
       ng-click... ng-class 
       ng-transclude="slota">

The content of li is sometimes just empty. Approx. one out of 20 tries. When I do the transclusion this way:

 $transclude(scope, function(clone) {
        element.append(clone);
    }, null, 'slota');

clone is sometimes empty, i.e. length===0, which normally means that I did a <slota></slota>.

I tried the AngularJS versions 1.7.2, 1.7.1, 1.7.0 and 1.6.10 and it doesn't work with 1.7.2 and 1.7.1. Every other version is just fine.

I checked the changes between 1.7.0 and 1.7.1 and tried to revert them in the 1.7..1 code. When I revert the change from this commitm, everything works as before.

So far, I was unable to reproduce this in a Plunkr.

AngularJS version: 1.7.1+

Browser: [ Firefox both Release and Nightly on Windows and macOS]

@gkalpak
Copy link
Member

gkalpak commented Jun 21, 2018

I am confused. Are you using $transclude() or ng-transclude.

And what exactly is the problem? Is it that the content is not transcluded sometimes (as if the slot was empty)? But the content is always transcluded correctly (i.e. not empty) with 1.7.0?

BTW, it might be helpful to have a code example, even if you can't reproduce the problem.

@Sennahoi
Copy link
Author

I'm using ng-transclude. That's exactly the problem we're facing, the content is sometimes not transcluded as if it was empty. The content is always transcluded with 1.7.0 or with 1.7.1 when I revert the changes from the linked commit.

@gkalpak
Copy link
Member

gkalpak commented Jun 21, 2018

Sounds like a DocumentFragment-related Firefox bug 😞
Does it happen with non-slotted transclusion?

@Sennahoi
Copy link
Author

We have a large number of transcluding components and just a few of them use slots. Because it only happens there, chances are it has something to do with slotted transclusion.

But it's hard to reproduce. One hour, I get the error after each reload, next hour, the error is gone for 20 reloads.

@gkalpak
Copy link
Member

gkalpak commented Jun 22, 2018

Any chance you could try the following and let me know if the problem goes away?
Change this line like this:

-slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName].childNodes, transcludeFn);
+slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, jqLite(slots[slotName].childNodes), transcludeFn);

@Sennahoi
Copy link
Author

That's great. Thanks for your quick response. I checked it with and without your change more than 10 times and it really seems let the bug go away. Thank you very much!

@gkalpak
Copy link
Member

gkalpak commented Jun 22, 2018

Awesome! Thx for getting back.
(Feel free to submit a pull request with the fix if you feel like it 😉 - if not I will submit it in the following days.)

gkalpak added a commit to gkalpak/angular.js that referenced this issue Jun 26, 2018
DOM nodes passed to `compilationGenerator()` will eventually be wrapped
in `jqLite`, when the compilation actually happens. In Firefox 60+,
there seems to be a `DocumentFragment`-related bug that sometimes causes
the `childNodes` to be empty at the time the compilation happens.

This commit works around this bug by eagerly wrapping `childNodes` in
`jqLite`.

NOTE:
The wrapped nodes have references to their `DocumentFragment` container.
This is "by design", since we want to be able to traverse the nodes via
`nextSibling` (in order to correctly handle multi-element directives).

Once the nodes are compiled, they will be either moved to a new
container element or the `jqLite` wrapper is release making them
eligible for garbage collection. In both cases, the original
`DocumentFragment` container should be eligible for garbage collection
too.

Fixes angular#16607
@gkalpak
Copy link
Member

gkalpak commented Jun 26, 2018

I submitted #16615.

@Narretz
Copy link
Contributor

Narretz commented Jun 27, 2018

I think we should also open a bug report at Firefox about this.

@gkalpak
Copy link
Member

gkalpak commented Jun 29, 2018

TBH, I don't feel we have enough details to create a useful bug report. All I know is that DocumentFragment.childNodes sometimes gets emptied out, but that sounds like those unactionable "It doesn't work" bugs 😁

Maybe if we knew the exact version it started failing, it might be useful.
@Sennahoi, do you know which exact version it started failing with?

@Sennahoi
Copy link
Author

Nope, sorry, I also thought about a bug report at Firefox but I understand the bug even less than you.

gkalpak added a commit to gkalpak/angular.js that referenced this issue Jul 4, 2018
DOM nodes passed to `compilationGenerator()` will eventually be wrapped
in `jqLite`, when the compilation actually happens. In Firefox 60+,
there seems to be a `DocumentFragment`-related bug that sometimes causes
the `childNodes` to be empty at the time the compilation happens.

This commit works around this bug by eagerly wrapping `childNodes` in
`jqLite`.

NOTE:
The wrapped nodes have references to their `DocumentFragment` container.
This is "by design", since we want to be able to traverse the nodes via
`nextSibling` (in order to correctly handle multi-element directives).

Once the nodes are compiled, they will be either moved to a new
container element or the `jqLite` wrapper is release making them
eligible for garbage collection. In both cases, the original
`DocumentFragment` container should be eligible for garbage collection
too.

Fixes angular#16607
@gkalpak gkalpak closed this as completed in bfdc917 Jul 9, 2018
gkalpak added a commit that referenced this issue Jul 9, 2018
DOM nodes passed to `compilationGenerator()` will eventually be wrapped
in `jqLite`, when the compilation actually happens. In Firefox 60+,
there seems to be a `DocumentFragment`-related bug that sometimes causes
the `childNodes` to be empty at the time the compilation happens.

This commit works around this bug by eagerly wrapping `childNodes` in
`jqLite`.

NOTE:
The wrapped nodes have references to their `DocumentFragment` container.
This is "by design", since we want to be able to traverse the nodes via
`nextSibling` (in order to correctly handle multi-element directives).

Once the nodes are compiled, they will be either moved to a new
container element or the `jqLite` wrapper is release making them
eligible for garbage collection. In both cases, the original
`DocumentFragment` container should be eligible for garbage collection
too.

Fixes #16607

Closes #16615
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants