Jump to content
GreenSock

failure13

GSAP + Angular JS

Recommended Posts

Well, simple as that...

How to work with angular efficently?

 

How to make tweens for something that haven't been shown on page yet and will be loaded dynamically later?

Link to comment
Share on other sites

What do you mean exactly? Do you want to animate something that doesn't exist yet?

When the objects are added to the DOM you can access them as you would with GSAP selectors or jquery ones since AngularJS also uses jquery.

Link to comment
Share on other sites

Well, i mean something like...

We have angular now working like it loads templates of code and then start to draw them, so before that happens they're not in dom, and any tween that was created for object inside that dinamycally created template won't work, right now i put my tweens like that:

$(document).ready(function() {
            $('button.btn, a.btn, .list-group a, .navbar li a, .nav li, .select .btn').each(function() {
                var buttonTL = new TimelineLite({paused:true});
                buttonTL.to(this, 0.35, {className: '+=hover', immediateRender: true}, 0);
                this.hoverTween = buttonTL;
            });
            $('button.btn, a.btn, .list-group a, .navbar li a, .nav li, .select .btn').hover(function() {
                this.hoverTween.play();
                console.log(this.hoverTween);
            }, function() {
                this.hoverTween.reverse();
            });
});

But i guess .ready is not the case, i'm really not sure about angular yet, just started to work with it, maybe it have something native to let GSAP work?

 

P.S. Objects that wasn't created dynamicaly are tweening fine, since they're in DOM from start.

Link to comment
Share on other sites

Hello failure13..

 

What you can do is use the on() method in jQuery. So if any element is added after the DOM is loaded and ready, the event will keep listening for any changes.

$(document).ready(function() {
     
     // placed selectors in variables
     var $hoverElements = $('button.btn, a.btn, .list-group a, .navbar li a, .nav li, .select .btn');

     $hoverElements.each(function() {
            var buttonTL = new TimelineLite({paused:true});
            buttonTL.to(this, 0.35, {className: '+=hover', immediateRender: true}, 0);
            this.hoverTween = buttonTL;
     });
        
     $hoverElements.on("mouseenter", function() {
            this.hoverTween.play();
            console.log(this.hoverTween);
     }).on("mouseleave", function() {
            this.hoverTween.reverse();
     });
});

You can also cache your jQuery selectors in variables. Also notice I'm using the event handlers mouseenter (rollover) mouseleave (rollout) ..

 

Quick note.. if you are using below jQuery version 1.7, then you will need to change on() to live()

 

:)

  • Like 1
Link to comment
Share on other sites

Check out egghead.io's Angular tutorials: https://egghead.io/technologies/angularjs They are starting to introduce GSAP. There is currently 1 free lesson and one Pro.

 

The egghead guys are true Angular experts. You can't go wrong.

Link to comment
Share on other sites

jonathan

Hi! :)

Your theory was perfect, and it still works for static, but it seem that with angular .on doesn't work as it should, still no animation for anything that was created dynamically via AngularJS...

 

My programmers said that they get data through angular controllers and then use ng-repeat to call for objects that should be created...To be honest i don't understand how angular works at all :(

 

carl schooff

Yep, i've just found yesterday evening this one:

http://www.thinkster.io/angularjs/bTlcxYTO2l/angularjs-animating-with-javascript

 

And this logic doesn't seem to work, i've done this so far:

var LavkaModule = angular.module('Shop', ['ngAnimate']);

LavkaModule.animation('.list-group a, .navbar li a, .nav li, .select .btn, .dropdown-menu li', function() {
    return {
        enter: function(element, done) {
            TweenMax.to(element, 0.25, {className: '+=hover', onComplete: done});
        },
        leave: function(element, done) {
            TweenMax.to(element, 0.35, {className: '-=hover', onComplete: done});
        }
    }
});

Maybe you could see something that i miss?

 

P.S. Oh and i haven't forgot to include angular.min.js and angular-animate.min.js, just in case

Link to comment
Share on other sites

So guys, anything more specific?

I still kinda lost to what aproach to choose, coz it seems pretty slow when i use directories and stuff like that.

 

I hoped that somebody else have already found good way of integrating.

Free lesson on egghead doesn't seem to work good / fast enough while loading page...

Link to comment
Share on other sites

All I can add is that the .on() stuff Jonathan mentioned sounded like a good idea, but it wouldn't have given you the old .live() behaviour I think he was referring to. To have it discover elements that aren't already on the page, you need to attach the listener to document and pass a selector like this:

 

$(document).on('mouseenter', 'button.btn, a.btn, .list-group a, .navbar li a, .nav li, .select .btn', function() {});

 

If you can provide a reduced demo with working Angular code, valid tween targets, and tweens that aren't working, then we'll take a look for sure. But otherwise, you probably don't have a great chance of finding someone to assist you with getting a handle of Angular in the GSAP forum.

  • Like 1
Link to comment
Share on other sites

Well i guess my problem is that when you create dynamically inside directive of angular stuff like:

$('button.btn, a.btn, .list-group a, .navbar li a, .nav li, .select .btn').each(function() {
    var buttonTL = new TimelineLite({paused:true});
    buttonTL.to(this, 0.35, {className: '+=hover', immediateRender: true}, 0);
    this.hoverTween = buttonTL;
});

This gets extreeeemly resourse intensive.

So the only way is to go hover only, therefore i need to get rid of all :hover, :active, :focus states in Bootrstap.

 

So i ended by multiple cursors of Sublime Text 2.

Just find some :hover, press ALT + F3 to select all of them inside file, then press HOME to go on the start of line and write .nojs class, that's it! :)

 

And in html i got this:

<body ng-app="Shop" class="nojs" gsap>
........
<body>

js have this directory to let it work on dinamically created parts of angular.js:

LavkaModule.directive('gsap', function() {
    return {
        link: function(scope, element, attrs) {

            // all hovers
            $('button.btn, a.btn, .list-group a, .navbar li a, .nav li, .select .btn, .dropdown-menu li').hover(function() {
                TweenMax.to(this, 0.25, {className: '+=hover'});
            }, function() {
                TweenMax.to(this, 0.35, {className: '-=hover'});
            });
        }
    }
});

This way it seems to work pretty good!

Hope it will help somebody :)

Link to comment
Share on other sites

I'm a little late on my response.. but Jamie is right.. by adding the context (document) to those elements your binding with on() ...

 

But it looks like AngularJS uses jqLite, and states that the on() method, when used in AngularJS.. does not support namespaces, selectors or eventData. see this link

 

And this link on AngularJS github, closed pull ticket about on/off.. where they state "The jQuery API for on() accepts a selector parameter (similar to how live() works). We don't support that."

 

:(

Link to comment
Share on other sites

Sorry, but my way actually seem to be horsecrap and doesn't work on dyanmic elements :(

 

jonathan

So reasonable question, what should i do then...?

Instead of on() i mean

Link to comment
Share on other sites

You should really start with angular and learn it without any animation.  The animation is the very very last step.  With that said, check out this fiddle.  This is how you animate something as a directive with a mouse event as well as I put it on a ng-repeat so you could see that the items don't actually exist in the dom yet and you can call them with the element attribute.

 

http://jsfiddle.net/Zuriel/HEhkH/

 

You also shouldn't call anything with $('whatever')  unless you plan on never reusing that component or directive for anything other than that sole purpose...  which is difficult to understand and takes a little bit of angular to grasp.   because in jquery you just bind to the class or ID of a item and animate it, but with angular you are creating reusable code.  So you want something to animate on hover, you want to aim to create it so that it can be reused.

 

 

 

I would check that fiddle out so you can see what i mean about creating a directive to do your animation, then I would read up on YearofMoo's animation article.  You really need to focus on just learning angular because there is alot of stuff you can do but you want to make sure you do it correctly from the start.  if you start doing alot of jquery body ready on load stuff then you are outside of angular at that point and anything goes! :)

 

YearOfMoo's Animation Article

Egghead.io  Videos

Thinkster build an angular app

 

Good Luck!

  • Like 2
Link to comment
Share on other sites

Hey man, thank you very much, it's very cool example, even though it doesn't do what i wanted, but at least it works at all...

I got one question nobody still can answer me about angular-gsap-snap.

 

For example, what if in your example instead of p i would have something like:

<ul id="cartActionPanel" class="list-inline">
    <li tmax twn="li">
    	<a href="">
    		<span class="svg20 iX" svg vector="i-x" swd="3.4" bdr="#1B1B1B"></span>
    		Clear
    	</a>
    </li>
    <li tmax twn="li">
    	<a href="">
    		<span class="svg20 iStar" svg vector="i-star" clr="#2B2B2B"></span>
    		Like
    	</a>
	</li>
    <li tmax twn="li">
    	<a href="">
    		<span class="svg20 iSave" svg vector="i-save"></span>
	    	Save as
	    </a>
	</li>
</ul>

How would i make something like $(this).find('svg') angular way in such situation?

I'm googling this for ages, reading docs, but still don't understand...

 

And if i do, how would i then make something like snapAnim = svg.find('*[fill]');

So that i can easily make tint effect with gsap using it?

 

P.S. It seems i've found working solution, not sure it's perfectly angular way...but it works!

LavkaModule.directive('tmax', function () {
    return function (scope, element, attrs, children) {
        // svg checker
        svgExist = false;

        switch (attrs.twn) {
            case 'li':
                element.bind('mouseover', function (children) {
                    children = this.children;
                    TweenMax.to(children, 0.4, {
                        className: '+=hover',
                        ease: Quad.easeOut
                    });
                    svg = angular.element(this.querySelector('svg'));
                    if (svg.length) {
                        console.log(svg);
                        svgExist = true;
                        snapAnim = svg.find('*[fill]');
                        TweenMax.to(snapAnim, 0.4, {
                            'fill': '#A21D20'
                        });
                    }
                });
                element.bind('mouseout', function (children) {
                    children = this.children;
                    TweenMax.to(children, 1.9, {
                        className: '-=hover',
                        ease: Quad.easeOut
                    });
                    if (svgExist == true) {
                        TweenMax.to(snapAnim, 1.9, {
                            'fill': '#2B2B2B'
                        });
                    }
                });
                break
        }

    }
});
Link to comment
Share on other sites

Ok guys, i have another question, now if i do it like that with angular:

 

html

<a tmax twn="svga" href=""><div class="svg24 iStar" svg vector="i-star" clr="#6b6b6b"></div></a>

JS:

LavkaModule.directive('tmax', function () {
    return function (scope, element, attrs, children) {
        // colors
        var lavkaRed = '#A21D20',
            orange = '#FC6608',
            white = '#FFFFFF',
            svgDark = '#2B2B2B',
            svgLighter = '#4D4D4D',
            svgLight = '#9e9e9e'
        ;
        // svg checker
        svgExist = false;

        // svg animation hover in
        function svgAnimIn(time, color) {
            if (svg.length) {
                svgExist = true;
                fillAnim = svg.find('*[fill]');
                strokeAnim = svg.find('*[stroke]');
                TweenMax.to(fillAnim, time, {'fill': color, ease: Quad.easeOut});
                TweenMax.to(strokeAnim, time, {'stroke': color, ease: Quad.easeOut});
            }
        };
        // svg animation hover out
        function svgAnimOut(time, color) {
            if (svgExist == true) {
                TweenMax.to(fillAnim, time, {'fill': color, ease: Quad.easeOut});
                TweenMax.to(strokeAnim, time, {'stroke': color, ease: Quad.easeOut});
            }
        };

        switch (attrs.twn) {
            case 'svga':
                element.bind('mouseover', function (children) {
                    svg = angular.element(this.querySelector('svg'));
                    svgAnimIn(0.4, lavkaRed);
                });
                element.bind('mouseout', function (children) {
                    svgAnimOut(0.5, svgDark);
                });
                break
        }

    }
});

And let's say i have complex multi-layer colorfull js, how would i get all those colors to apply later on with mouseout (instead of svgDark)?

 

Bad thing is - i can't create var t = TweenMax object to use .play() & .reverse(), for perfomance sake (a loooot of dinamically created objects)...

 

So i guess i should save all the original colors to array somehow?

Any idea would be appreciated!

 

P.S. Sorry for lack of fiddle, i still burn on work here with no time)

Link to comment
Share on other sites

  • 4 months later...

Failure13,

The reason none of your code was working is because the .on() method runs outside the context of Angular. Angular is not aware of any changes made by third party libraries. This includes jqLite, jQuery, GreenSock, etc. To make Angular aware of any changes made by a third-party library, a digest cycle must run.

 

The easiest way to trigger a digest is to call scope.$apply(). However, if Angular is already watching something that you modified, you may get a digest already in progress error. To get around this, use $timeout with a 0 delay instead. $timeout is injected into your directive/provider, and will automatically call $apply on the next digest.

 

Check out this Plunk

 

http://plnkr.co/edit/Z28hiklSk8IsyQ2Bi45s?p=preview

 

Notice how the first box does not respond without a $timeout or $apply call.

  • Like 3
Link to comment
Share on other sites

To anybody who is starting to learn Angular with a jQuery background, please read these StackOverflow responses. It will really help put you in the right mindset. jQuery really seems to hamper peoples ability to learn Angular, and this might save you a bunch of time.

 

http://stackoverflow.com/questions/14994391/how-do-i-think-in-angularjs-if-i-have-a-jquery-background

  • Like 6
Link to comment
Share on other sites

  • 1 year later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×