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

ngAnimate short circuts Dom removal during remove, causing off by one errors (ng339 error) #8796

Closed
mpolichette opened this issue Aug 27, 2014 · 9 comments

Comments

@mpolichette
Copy link

I think was experiencing a really nasty bug causing an error: TypeError: Cannot read property 'ng339' of undefined

This error happens while removing elements.
I think I've found the reason:

  1. While removing elements, angular does a child querySelector of '*' to get all the elements beneath the to be removed element.
  2. It then iterates over that HTMLCollection ('descendants') like an array to remove it's cached data about the element.
  3. While removing cached data, "$destroy" events are fired on elements
  4. $destroy events trigger a cancel() on animations which are currently running, causing them to short circuit their DOM operation

If before this remove an element had started a leave animation, (E.G. by ng-if condition changing), that element will be removed immediately.

  • The removal causes the HTMLCollection to remove it also, which mutates the length of the HTMLCollection 'descendants' in the middle of the original removal loop, leading to an off by one error in the looping logic.

In the end, descendants.length is reduced but the loop variable l is kept at the original value. Once the loop variable i is larger than descendants.length, it passes undefined as the element to jqLightRemoveData which tries to access element.ng339
- https://github.com/angular/angular.js/blob/master/src/jqLite.js#L294

I'm not sure what the correct solution would be, as I have not been too involved in the development of angular. I've come up with three possible leads:

  • Update our iteration cap if the the HTMLCollection's length changes.
  • Some sort of check within ngAnimate to prevent short circuiting if it is going to be removed
  • Some pre-check on element before accessing element.ng339

Thanks!
-Matt


PR: #8958

@matsko matsko self-assigned this Aug 28, 2014
@Narretz Narretz added this to the Backlog milestone Aug 28, 2014
@dferrin
Copy link

dferrin commented Aug 31, 2014

I can confirm this issue using 1.2.23. It also happens on ng-include inside ng-switch.

@matsko
Copy link
Contributor

matsko commented Aug 31, 2014

Can you guys create a plunkr for this please?

@dferrin
Copy link

dferrin commented Aug 31, 2014

I just realized though that the bug is still happening even though ngAnimate is removed from the list of dependant modules.

@matsko
Copy link
Contributor

matsko commented Sep 4, 2014

@matsko matsko modified the milestones: 1.3.0-rc.1, Backlog Sep 4, 2014
@mpolichette
Copy link
Author

👍

Using those files solved the problem in my app! Can't wait for it to be included in a release!

Thanks @matsko you rock!

matsko added a commit to matsko/angular.js that referenced this issue Sep 5, 2014
… during digest

Prior to this fix, if the element is removed before the digest kicks off then it leads
to an error when a class based animation is run. This fix ensures that the animation will
not run at all if the element does not have a parent element.

Closes angular#8796
@dferrin
Copy link

dferrin commented Sep 6, 2014

👍

It also solved my problems. Hope this fix will land in 1.2.24!
Thanks :)

@jeffbcross jeffbcross modified the milestones: 1.3.0-rc.1, 1.3.0-rc.2 Sep 9, 2014
@tbosch tbosch modified the milestones: 1.3.0-rc.2, 1.3.0-rc.3 Sep 15, 2014
@jeffbcross jeffbcross modified the milestones: 1.3.0-rc.3, 1.3.0 Sep 22, 2014
@jeffbcross jeffbcross modified the milestones: 1.3.0-rc.5, 1.3.0 Sep 29, 2014
@IgorMinar
Copy link
Contributor

@p3rsist are you saying that you see the issue in 1.2.x? the fix @matsko suggested fixes code that is not present in 1.2.x.

@dferrin
Copy link

dferrin commented Oct 1, 2014

@IgorMinar Yes. I'm using 1.2.25.
I have a directive inside an ng-switch-when directive. When I do some changes to the scope models inside that directive (saving data to the server and updating the models) and I switch view (going to another ng-switch view) and go back again to that same ng-switch-when I get this ng339 error.

Is this #9370 issue exhibits symptoms of the same underlying problem?

matsko added a commit to matsko/angular.js that referenced this issue Oct 3, 2014
… during digest

Prior to this fix, if the element is removed before the digest kicks off then it leads
to an error when a class based animation is run. This fix ensures that the animation will
not run at all if the element does not have a parent element.

Closes angular#8796
@matsko
Copy link
Contributor

matsko commented Oct 7, 2014

@p3rsist would you mind creating a new issue for 1.2 and assigning to me. The underlying issue here is different since it only relates to 1.3.

@matsko matsko closed this as completed in 613d0a3 Oct 7, 2014
bullgare pushed a commit to bullgare/angular.js that referenced this issue Oct 9, 2014
… during digest

Prior to this fix, if the element is removed before the digest kicks off then it leads
to an error when a class based animation is run. This fix ensures that the animation will
not run at all if the element does not have a parent element.

Closes angular#8796
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.