angular / angular.js

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

ngIf with ngAnimate adds ng-enter class too late in Safari 9.0.1 #13386

Closed eXaminator closed 8 years ago

eXaminator commented 8 years ago

Hi,

I just stumbled across a strange behavior in ngAnimate.

I have build a very simple "collapsible" which removes an element via ng-if and animates its max-height on enter and leave. This works as expected unless I also add an ng-class to a parent which sets the is-open class when the collapsible was opened which also has an animation.

When viewing the plunker in Safari (I have 9.0.1) you will see a very short "flicker". It seems that ng-if appends the DOM element before the class is set.

Here is a short gif where you can see the problem. When clicking the toggle button it will shortly show the element at full height before collapsing it to max-height: 0 (as per the ng-enter class) and then it starts growing again with the animation.

flicker

As soon as you remove the ng-class the flicker problem is resolved. This problem doesn't seem to occur in other browsers (at least not in chrome).

http://plnkr.co/edit/yrebsEs80kPaS90rk0oE

eXaminator commented 8 years ago

It doesn't seem do be directly connected to ng-class as changing

<div class="outer" ng-class="{'is-open': ctrl.toggle}">

to

<div class="outer {{ ctrl.toggle ? 'is-open' : '' }}">

yields the same results.

kazimierasc commented 8 years ago

This problem seems to be related with issue https://github.com/angular/angular.js/issues/12507 in the sense that it applies to the same browsers and was also introduced from 1.4.x versions of angular. I tried your plunker with 1.3.14 and it seems to work fine on Safari 9.0.1.

Narretz commented 8 years ago

I can't confirm it, but it does look similar to issue #12507.

eXaminator commented 8 years ago

I forgot to mention this was on Mac OS X, not iOS.

Narretz commented 8 years ago

Sounds also similar to https://github.com/angular/angular.js/issues/12969 @eXaminator can you test this plnkr please? http://plnkr.co/edit/UeScgitwkNM2xqKxL8WO?p=preview

I've added a new style,

.expandable.ng-enter-prepare {
  max-height: 0px;
}

that should make sure the element is hidden before the animation starts.

You can also test with these files directly:

https://rawgit.com/Narretz/angular.js-builds/master/angular.js
https://rawgit.com/Narretz/angular.js-builds/master/angular-animate.js
matsko commented 8 years ago

@eXaminator this is, unfortunately, by design. ngAnimate adds a frame in between the parent ngClass element and the child ngIf. The reason for this is to allow CSS classes to update on the page at the right time in time for the child animations to detect and run properly.

There are two ways to work around this:

  1. Use Narretz's example of using ng-animate-prepare to set pre-styled values which are applied before any of the digests run to trigger animations. Note that this code isn't in the 1.4 branch, but we can add it in here to help with issues like this.
  2. Setup a CSS class to whitelist animations so that traditional, non-ngAnimate invoked, animations (transitions/keyframes) can still operate without ngAnimate interfering.
// app.js
.config(function($animateProvider) {
  $animateProvider.classNameFilter(/use-ng-animate/);
});
    <div class="outer" ng-class="{'is-open': ctrl.toggle}">
      <button ng-click="ctrl.toggle = !ctrl.toggle">Toggle</button>
      <div ng-if="ctrl.toggle" class="expandable use-ng-animate">
        <div class="content">some content</div>
      </div>
    </div>

NgAnimate in Angular 2.0 will be doing a different approach. We will also work to get that behavior into future versions of 1.x.

Closing for now. Please reopen if there is still something that hasn't been covered.

eXaminator commented 8 years ago

@matsko @Narretz Thanks for all the info on this. I will have a look at this at some point, but we'll probably wait for 1.5 to use the prepare method, which sounds like it is the best approach for this. We're waiting for some of the 1.5 features anyway, hopefully the release won't take too long :)

tdmichaelis commented 8 years ago

Awesome, this fixed the issue I was having in safari