Friday, September 1, 2017

Angular 1.x ngAnimate in Shadow DOM doesn't register animation times or add enter/leave classes

Leave a Comment

I've been trying to work out solutions for a few hours now - all the duplicates in SO don't seem to work for me as they mostly recommend either trying different versions of ng-animate/angular or adding the transition/animation in the relevant classes so that ngAnimate can handle their timings right.

My problem is that all of this was working, and I had all the properties in the correct locations - but now I am migrating our Chrome extension to work under a Shadow DOM encapsulation.

Notes:

  • Shadow DOM is probably the culprit, but I'm not sure why or how to fix it. It might also be irrelevant or only play a minor part in the actual problem (it is probably due to bad DOM handling in Shadow DOM + angular)
  • I am bootstrapping my app manually later in the lifecycle of the extension injection since it is supposed to only start up after a callback. This might also be the culprit

Here is a plunker - I think I have the case isolated as much as I could here. Clicking the links should open/close the divs after them in a slide down/up animation, respectively. Currently they just open up immediately.

Here are the relevant styles:

.view-container {   position: absolute;   top: 70px;   bottom: 0;   background: white;   transition: all 0.4s 0.2s ease-in-out;   overflow-y: hidden;   // slide animation   &,   &.ng-hide-remove,   &.ng-hide-remove-active {     max-height: 500px;   }    &.ng-hide {     max-height: 0;   } } 

Here is the template:

<div ng-show="rchCtrl.view == 'flag'"   class="view-container">   <div ng-include="'/templates/extension/article-flag-form.html'"     ng-if="rchCtrl.view == 'flag'"     ng-controller="ArticleFlagCtrl as flg"     class="article-flag"></div> </div> 

Bower file:

"dependencies": {     "jquery": "^2.2.1",     "trackjs": "^2.8.3",     "angular": "^1.6.0",     "qtip2": "^2.2.1",     "ng-qtip2": "1.3.3",     "angular-ui-router": "^0.2.18",     "angular-cookies": "^1.6.0",     "angular-resource": "^1.6.0",     "bootstrap": "^3.3.7",     "angular-animate": "^1.6.0"   },   "resolutions": {     "angular": "1.6.6"   } 

My angular init section:

app = angular.module(APP_NAME, ['template-cache', 'ui.router', 'ngCookies', 'geCommon', 'ngAnimate'])  // ...  angular.bootstrap(shadow.querySelector('#ge-ext'), [ APP_NAME ], { debugInfoEnabled: true }) angular.resumeBootstrap() 

But after all this, the intermediate classes are never added/removed, and the animation isn't working - hide/show display is immediate.

2 Answers

Answers 1

Take a look if this is what you are trying to achieve:

https://plnkr.co/edit/0rmEfPlsn3GsK6rtLalP?p=preview

I did some tweaks on the menu.html and style.css. Basically, what I did was remove things like ng-hide/ng-show from the elements that were supposed to have animation and instead I've put ng-class to manipulate the visibility while maintaning the animation. The reason that ng-hide/ng-show aren't the best ideas for animation is that they apply display: block property to your element, thus any transition applied to them will not work. visiblity: visible/hidden is the key if you want to use css transitions.

// New styles #menu li {   transition: all 0.4s ease-in-out; }  #menu li.invisible {   height: 0;   opacity: 0;   visibility: hidden; }  .article-feedback, .article-flag {   /* Zero height in normal start */   height: 0;   transition: all 0.4s ease-in-out; }  .article-feedback.visible, .article-flag.visible {   /* When visible, height goes to 100px */   height: 100px; } 
<ul id="menu"   class="list-unstyled"   ng-class="{'view-open': rchCtrl.view != null}"   ng-show="rchCtrl.menuOpen"   ng-controller="RelatedResearchesCtrl as rchCtrl">   <li ng-class="{'invisible': rchCtrl.view && rchCtrl.view != 'feedback'}">     <a fake-click       ng-click="rchCtrl.openView('feedback')">       Send feedback &amp; ideas     </a>     <span class="icon-close"       ng-show="rchCtrl.view == 'feedback'"       ng-click="rchCtrl.openView(null); $event.stopPropagation()">       &times;     </span>      <!-- I've removed the ng-show and added ng-class, so transitions will work -->     <div class="view-container">       <div style="background: red;"         ng-class="{'visible': rchCtrl.view == 'feedback'}"         class="article-feedback"></div>     </div>   </li>   <li ng-class="{'invisible': rchCtrl.view && rchCtrl.view != 'flag'}">     <a fake-click       ng-click="rchCtrl.openView('flag')">       Flag this page     </a>     <span class="icon-close"       ng-show="rchCtrl.view == 'flag'"       ng-click="rchCtrl.openView(null); $event.stopPropagation()">       &times;     </span>     <div class="view-container">        <!-- I've removed the ng-show and added ng-class, so transitions will work -->       <div style="background: blue;"         ng-class="{'visible': rchCtrl.view == 'flag'}"         class="article-flag"></div>     </div>   </li> </ul> 

Let me know if there's any other questions about my plnkr.

Answers 2

I think you are missing this from the css part:

.ng-hide:not(.ng-hide-animate) {   /* These are just alternative ways of hiding an element */   display: block!important;   position: absolute;   top: -9999px;   left: -9999px; } 

as mentioned here and in Bruno Poeta answer.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment