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

ng-animate animations are not triggered atomically between enter and leave on ng-view #3404

Closed
gustly opened this issue Jul 31, 2013 · 12 comments

Comments

@gustly
Copy link

gustly commented Jul 31, 2013

We are running into an issue in our AngularJS 1.1.5 app related to how ng-animate triggers the animations for enter and leave on the ngView directive.

We are doing a "slide left" animation using a CSS transition. We're doing the usual thing where we put an initial state and a transition with a duration on the .slide-left-enter and .slide-left-leave classes, and an end state on the .slide-left-enter-active and .slide-left-leave-active classes. That part is working fine.

The problem is that sometimes there can be a delay of several milliseconds between when the animation is triggered on the "enter" element and on the "leave" element. This is because it takes an unpredictable amount of time for the JS interpreter to get from one of the addClass calls to the other one. If you hit a garbage collection, for example, it could be a relatively long time.

This causes strange artifacts in our animations. See http://plnkr.co/A2z1mAQ0D6P6RJIX7fDJ for a small example.

We would like to propose a new animation type that could be added in addition to "enter" and "leave" for ngView and any other directives that might make sense. We think it could be called "change".

The idea for "change" is that it would add classes such as .slide-left-change and .slide-left-change-active directly on the ngView element. Then we could rewrite our CSS to be triggered on this class change instead.

For example, this CSS

.slide-left-enter {
    left: 100%;
    transition: 1s linear left;
}
.slide-left-enter.slide-left-enter-active {
    left: 0;
}

.slide-left-leave {
    left: 0;
    transition: 1s linear left;
}
.slide-left-leave.slide-left-leave-active {
    left: -100%;
}

would become

.slide-left-change .slide-left-enter {
    left: 100%;
    transition: 1s linear left;
}
.slide-left-change.slide-left-change-active .slide-left-enter {
    left: 0;
}

.slide-left-change .slide-left-leave {
    left: 0;
    transition: 1s linear left;
}
.slide-left-change.slide-left-change-active .slide-left-leave {
    left: -100%;
}

The idea is that now there is just one addClass call that triggers both animations at exactly the same moment.

@gustly
Copy link
Author

gustly commented Aug 1, 2013

We have posted a $250 bounty for the solution of this issue on Bountysource.

@matsko
Copy link
Contributor

matsko commented Aug 1, 2013

Instead of a change animation, you could just handle the entire animation with the leave animation.

Setup your CSS like this:

.red {
  background: red;
  color: white;
}
.blue {
  background: blue;
  color: white;
}
.wrapper { 
  overflow-x:hidden;
  position:relative;
  white-space:nowrap;
  margin:0;
}
.wrapper > div {
  margin:0;
  display:inline-block;
  width:100%;
}
.wrapper > .slide-left-leave {
   transition:1s linear all;
}
.wrapper > .slide-left-leave-active {
   margin-left:-100%;
}

Since the next page will always be placed after the previous one in terms of DOM ordering, the slide animation will always have both areas animating at the same time.

Here's your demo:
http://plnkr.co/edit/DOuiEYVPcNMWj8PWRDLv?p=preview

@gustly
Copy link
Author

gustly commented Aug 1, 2013

That's an interesting workaround. Unfortunately it doesn't fully cover our use case, which is a little bit more complex than the original description. In our Plunker, you will notice that we animate using -webkit-transform and translate3d() instead of left. We used left above because we thought it would be a simpler way to explain the situation.

We are building a mobile web application, so we want to be able to use GPU-accelerated transforms as our animation. Our CSS is closer to something like this:

.slide-left-enter {
    -webkit-transform: translate3d(100%, 0, 0);
    -webkit-transition: 300ms ease-in transform;
}
.slide-left-enter.slide-left-enter-active {
    -webkit-transform: translate3d(0, 0, 0);
}

.slide-left-leave {
    -webkit-transform: translate3d(0, 0, 0);
    -webkit-transition: 300ms ease-in transform;
}
.slide-left-leave.slide-left-leave-active {
    -webkit-transform: translate3d(-100%, 0, 0);
}

We've also considered some different transforms, such as rotations of a cube face, that would definitely require both animations to happen.

Since translate3d() doesn't push around sibling elements the same way an inline-block div's left property does, we most likely need a solution that synchronizes both animations.

To be clear, we are really looking for a global solution that allows enter and leave animations to be defined fully independent of each other, yet be triggered synchronously.

@mgcrea
Copy link
Contributor

mgcrea commented Aug 29, 2013

@gustly I've encountered the same timing issues as well (see #3629)

I've come up with a custom ngAnimate decorator (that overrides parts of the official one) to support css events instead. It fixed all my issues.

See https://github.com/mgcrea/angular-touch-nav/blob/edge/src/scripts/services/animateDecorator.js#L94

@matsko
Copy link
Contributor

matsko commented Aug 29, 2013

@mgcrea I think @gustly's issue is more that the enter/leave animations are off each time by a X milliseconds while with your case your animations are getting cut by a few milliseconds and ending prematurely. The next ngClass PR fix should your issue. As for @gustly lets revisit this once that PR is in since it changes the timeouts around which may reduce the gap between enter and leave animations. I'll provide a link once I get that PR ready in a few hours.

@matsko
Copy link
Contributor

matsko commented Oct 1, 2013

@gustly @mgcrea ngAnimate doesn't use timeouts anymore. I'm not certain however if this fixes your animation code to be fully atomic. Can you try the latest snapshot code: http://code.angularjs.org/snapshot/.

@matsko
Copy link
Contributor

matsko commented Oct 14, 2013

@gustly RC3 is out now and there has been a nice performance boost to ngAnimate. Can you take a look to see if things are any closer to being atomic?

@mikefrederick
Copy link

@matsko we (gustly) don't actually have anyone actively working with angular at the moment, and we stripped all of our animations because we felt they were too flaky.

I will try to set aside some time in the near future to test out RC3 with the animations we were using.

@matsko
Copy link
Contributor

matsko commented Nov 6, 2013

@gustly @mikefrederick animations are now processed in a direct queue. This means that each animation that is run within 10ms of each other will kick off at the same time. This should make things atomic.

@matsko
Copy link
Contributor

matsko commented Nov 22, 2013

@gustly 1.2.2 queues up all animations so they run in one go. This should be as atomic as it gets.

@matsko
Copy link
Contributor

matsko commented Dec 4, 2013

Closing this for now. Please reply if something comes up.

@matsko matsko closed this as completed Dec 4, 2013
@rappo
Copy link

rappo commented Oct 15, 2014

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

No branches or pull requests

5 participants