angular / angular.js

AngularJS - HTML enhanced for web apps!
https://angularjs.org
MIT License
58.85k stars 27.52k forks source link

ng-enter animation of children/siblings doesn't work #13250

Closed Burgov closed 8 years ago

Burgov commented 8 years ago

See the following fiddle: https://jsfiddle.net/bgkdd9ma/1/

what should happen is that on open, the red box slides open, and the content below it slides down, and on close, the opposite.

The ng-leave animation works perfectly, but as you can see, the siblings animation on enter does not work.

Interestingly enough in my code even the child animation does not work, but it does in the example.

You can see I left a debugger statement in the code. If you open up the console and trigger it, then step forward to the point just after the element is entered into the DOM, and add a attribute modifications breakpoint on the element itself, you will see that by hitting play, it does work (although you will also see that it does a closing animation prior to the opening one)

Narretz commented 8 years ago

I wonder if that's not a different issue. I've added a background-color property to my-directive.ng-enter, and to me it looks like the translation property is applied correctly. It's just that my-directive immediately has height: 100px, and only the contained div has an actual animation: http://plnkr.co/edit/TqSKnuW6c8nQt3bSCuFU?p=preview

wesleycho commented 8 years ago

I think we have seen something like this reported against various components in UI Bootstrap as well, all dealing with parent elements that use $animate/$animateCss along with children elements also doing the same - it should be noted that this is not exclusive to enter, but also occurs when adding/removing classes.

This is an ngAnimate regression from 1.3 to 1.4 as far as I can tell.

I have been meaning to look into this at some point, but I've been underwater with prepping UI Bootstrap for a 1.0 release :( .

Narretz commented 8 years ago

This is definitely not an issue with ngAnimate, at least not with what animate can do at the moment.

The thing is that in the example, the my-directive element has a fixed height of 100px. When the container is inserted in the DOM, it is immediately 100px tall, which pushes its siblings (test) down 100px. The transform: translation for the enter animation of the siblings is effectively translateY(0) - but the items are already at their 0 position, so they don't move. It works for the leave (translateY(-100px)) animation, because the my-directive element is only removed when the animation is over, so the siblings animate based on their current position and end up at their new position.

The only way I made it work with the enter animation was to make the my-directive element position: absolute. That way, its height does not push the siblings down immediately, and we can translate the height of the container. It's not perfect, as switching to leave during enter will push the items further down, because the position:absolute is removed. http://plnkr.co/edit/2Ci9kIyLngyLm9V7pl4B?p=preview

It's probably the best to animate the actual my-directive, including its height.

Burgov commented 8 years ago

I was hoping this would be solved in 1.5, but unfortunately, it doesn't seem to be: https://jsfiddle.net/bgkdd9ma/2/

Burgov commented 8 years ago

@wesleycho i tried running the example in ng 1.3.9, but that doesn't make any difference

Narretz commented 8 years ago

@Burgov I've come to the conclusion that your original example is not an angular problem, see my posts above. Does the explanation make sense to you?

Burgov commented 8 years ago

@Narretz

"The transform: translation for the enter animation of the siblings is effectively translateY(0) - but the items are already at their 0 position, so they don't move."

The enter animation if the siblings starts at -100px: image

Then in ng-enter-active the values are set to 0. In the leave animation, the exact opposite happens (and works fine).

I really think this is buggy behaviour and the issue should be reopened.

Burgov commented 8 years ago

@Narretz is the above enough to reopen this ticket?

Narretz commented 8 years ago

@Burgov I don't think so. Maybe this is a misunderstanding. When you set a style in ng-enter it is not setting a starting point for a property, and ng-enter-active is not the ending point. What you set in ng-enter-active overwrites what you set in ng-enter. That's what I meant with the siblings have effectively translateY(0).

If this behavior is possible without ngAnimate, then we can reopen this issue.

gkalpak commented 8 years ago

FWIW, I believe this should work as @Burgov expects (but it obviously doesn't).

That said, it might be a browser thing. The my-directive.<some-class> ~ div doesn't seem to get applied by the browser - maybe the ~ rules are not evaluated between adding the preparation classes (e.g. ng-enter/ng-leave) and adding the active classes (e.g. ng-enter-active/ng-leave-active).

Not sure if ensuring that an animation frame has passed before applying the active classes would help. (Unless we are already doing that :/)

Narretz commented 8 years ago

My apologies, it is indeed expected that you can set a starting point with ng-enter and an end point with ng-enter-active. Here's a version that works: http://plnkr.co/edit/TqSKnuW6c8nQt3bSCuFU?p=preview

It adds

my-directive.ng-enter-active ~ div {
    transition: transform 1s;
}

when it was previously on

my-directive.ng-animate ~ div {
    transition: transform 1s;
}

I can't say exactly what the problem with the previous code is, but the change makes sense when you think about this: the translateY(-100px) is supposed to be the starting point of the animation, but it should not be animated! When the transition is on .ng-animate, the browser tries to animate the sibling to -100px. I assume that this interferes with the actual animation.

gkalpak commented 8 years ago

I can't say exactly what the problem with the previous code is

@Narretz , I think you already did :stuck_out_tongue:

the translateY(-100px) is supposed to be the starting point of the animation, but it should not be animated!

That's exactly the problem. The elements are not set to translateY(-100px) immediately, but start to animate towards there (because of the .ng-animate ~ div { transition: ... } style). Before they get a change to go too far with their animation, the .ng-enter-active ~ div { transform: translateY(0); } style kicks in and gets them back to 0.

:+1:

Burgov commented 8 years ago

@gkalpak thanks! It makes sense now that I think it through. Normally, with animations on the element itself, it is created with the ng-enter class, so the animation does not run - then ng-enter-active is added and it animates.

The siblings already exist, so when the element is added, they animate. That also explains that it worked better when I was debuggin the code - the breakpoint caused it to finish its enter animation.