3

I'm new to Angular, so if I'm doing any of these steps all wrong please set me straight.

I am trying to get the clamps on the left and right side of my website to animate in on initial page load. Here it is in production: https://www.robotsidekick.com

As you can see it currently works (yay). However I'm not happy with the hack that I'm using. Here is the pertinent code:

In my controller I am listening for $routeChangeStart and if it's the first time through I call:

setTimeout(function() {
    angular.element(document.querySelector('.robotarmleft')).addClass('animate-in');
    angular.element(document.querySelector('.robotarmright')).addClass('animate-in');
}, 0);

That grabs the two clamps, adds the class animate-in which has the following CSS properties:

.robotarm {
    margin-left: -2048px;
    margin-right: -2048px;
}

.animate-in {
    -webkit-transition: all 2s ease;
    -moz-transition: all 2s ease;
    -o-transition: all 2s ease;
    transition: all 2s ease;

    margin-left: -1300px;
    margin-right: -1300px;
}

So the arms are (hopefully) off screen, and they animate in.

If however I add the class to the robot arms not in that setTimeout the animation isn't triggered at all.

Why does that addClass have to be in a setTimeout to work? Should I kick off the animation in some other onPageLoadTheFirstTime type even for Angular? Mostly looking for the right way to do this sort of thing not so much a well this other hack works great too.

Thanks for the help!

xbakesx
  • 13,202
  • 6
  • 48
  • 76
  • 2
    First thought, you should be using `$timeout` to stay in an angular digest cycle vs. `setTimeout`. The timeout is probably necessary because it's gets executed before the DOM has rendered, meaning your `angular.element(..)` calls return `[]`. I had this issue also but was using `ui-router`, and it provides and event called `$viewContentLoaded` which isn't called until the view is rendered. However, using `$timeout` to delay code a digest cycle is a very common workaround to a lot of problems, [example](http://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful). – Tony May 07 '15 at 23:00
  • Thanks for the $timeout tip! You should write up an answer to get credit. I'm pretty sure (but haven't written it up) that the problem is that the class gets added (correctly) but before the DOM is fully loaded. So the css that is applied doesn't animate, it just sets the location. So however it is best to do stuff after DOM is ready would fix it. – xbakesx May 08 '15 at 02:36
  • Putting hooks into an `$on($viewContentLoaded)` callback made the animation happen as expected. Basically waiting for the DOM to be ready THEN adding the css so the transition actually triggers. (I also did more appropriate angular things by using `ng-class` instead of adding classes in the controller) – xbakesx May 08 '15 at 15:40
  • Well I'm glad that solved the problem. Since it's confirmed as a solution I posted it as an answer as well. Happy coding! – Tony May 08 '15 at 15:46

1 Answers1

2

First thought, you should be using $timeout to stay in an angular digest cycle vs. setTimeout().

The timeout is probably necessary because it gets executed before the DOM has rendered, meaning your angular.element(..) calls return []. You'll have to listen for an event that gets called after the DOM has rendered. Something like ui-router's $viewContentLoaded event.

Additionally, using $timeout to delay code a digest cycle is a very common workaround to a lot of problems, example.

Community
  • 1
  • 1
Tony
  • 2,473
  • 1
  • 21
  • 34
  • 1
    Note to future readers, `angular.element(...)` did in fact return the expected elements, despite the DOM not being ready. However that meant that when the DOM was rendered the css class was already there, so there was no CSS transition to apply, so no animation. – xbakesx May 08 '15 at 18:31