Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
Robert Wildling

Is it possible to use a function within onCompleteParams?

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

This might not really be a GSAP specific problem, but more a Javascript related one, nevertheless I would like to ask here for help, it that is ok.

(The CodePen unfortunately throughs an error, and I do not see the reason why...)

 

I like to save DOM elements to a SETTINGS object like this:

 

```

var SETTINGS = SETTINGS = {
  intro: {
    topics: {
      singer: {
        btn: {
          el: document.querySelector('.c-topic--singer'),
          params: {
            right: "5%",
            onComplete: resetTxt,
            onCompleteParams: [ SETTINGS.intro.topics.singer.btn.el ]
          },
        },
      },
    },
  },
}

```

 

The TweenMax then looks like this:

 

```

TweenMax.to( SETTINGS.intro.topics.singer.btn.el, 2, SETTINGS.intro.topics.singer.btn.params );

```

 

The idea is, that the animated element (a button) is set to another position as soon as it is finished. Therefore I'd like to set a self reference in the SETTINGS object in order not to call document.querySelector twice. But that doesn't work as I hoped, and reading up on google I find posts that use a function for callback parameters, but in cases where there is not array needed.

 

So I tried something like this:

 

```

onCompleteParams: function() {
    var arr = push(this.intro.topics.singer.btnTxt.el);
    return arr;
}

``` 

 

But no success... 

 

I am not a JS pro by any means, so I am pretty sure, there is something fundamental I do not grasp about JS objects and self referencing.

 

Maybe somebody of you finds a moment to explain, how I could use such a self reference within an array? And maybe also, if it is in general a good idea to build up such a SETTINGS object, anyway? Or would there be better approaches for SPAs?

 

Thanks in advance!

Best, Robert

See the Pen JNxwZM by rowild (@rowild) on CodePen

Link to comment
Share on other sites

Hello Robert Wildling

 

Im not near my computer but ...

 

onCompleteParams only accepts an array that passes the parameters to your onComplete callback function.

 

Taken from the Tweenmax Docs: https://greensock.com/docs/#/HTML5/GSAP/TweenMax/

  • onCompleteParams : Array - An Array of parameters to pass the onComplete function. For example,TweenLite.to(element, 1, {left:"100px", onComplete:myFunction, onCompleteParams:[element, "param2"]}); To self-reference the tween instance itself in one of the parameters, use "{self}", like:onCompleteParams:["{self}", "param2"]

Also keep in mind that GSAP already uses document.querySelector()  by default in its tween target behind the scenes. So you don't need to call document.querySelector() at all and should just pass the target as a string '.c-topic--singer' for your el property.

 

TweenMax to() : https://greensock.com/docs/#/HTML5/GSAP/TweenMax/to/

  • to() target: Object
    Target object (or array of objects) whose properties should be affected. When animating DOM elements, the target can be: a single element, an array of elements, a jQuery object (or similar), or a CSS selector string like “#feature” or “h2.author”. GSAP will pass selector strings to a selector engine like jQuery or Sizzle (if one is detected or defined through TweenLite.selector), falling back to document.querySelectorAll().

I hope this helps :)

 

 

  • Like 5
Link to comment
Share on other sites

The onComplete callback functions are setup so that this inside the callback refers to the tween that called the function.

So knowing that you can do this.target to get the element that was being tweened.

Also you can pass in the special string "{self}" in your onCompleteParams, but Its easier just to use this in the function.

 

Both methods are illustrated in the resetText function below (open the pen in a new window and view console).

See the Pen EmrJZZ?editors=0011 by GreenSock (@GreenSock) on CodePen

 

  • Like 4
Link to comment
Share on other sites

Thank you, Jonathan and Carl, for your help!

 

Could you nevertheless help me understanding how a self reference works within a object? The "onCompleteParams" also need a config that is saved as "initialPosition:  {[..some params...]}" within that object, and I would need that config in the onComplete function, as well.

 

```

SETTINGS = {

   intro {

      topics. {

         singer: {

            btnTxt: {
               el: '.c-topic--singer',  // <-- thanks for that hint!!!
               params: {

                   initialPositon: { ... },

                   activePosition: {

                        ...

                       onComplete: resetTxt,
                       onCompleteParams: [

                           SETTINGS.intro.topics.singer.btn.params.initialPosition  // <-- *1)

                       ]  

                   }
              },
        },
   },
}

```

 

*1) Here, I would like to re-assign the initialPosition params...

 

SETTINGS is build up on page call, there is no separate function like buildSetting, which assigns values to all the keys. But I have a guts feeling that this needs to be done... Or do you know of any way to refer to the value of another key within the object?

 

Thanks a lot!

 

Link to comment
Share on other sites

Sorry for the delay. I was hoping someone would be able to jump in with some sort of a solution.

I believe the root of your problem is exactly where you illustrate it above: SETTINGS object can't reference values nested in objects inside it while it is being constructed like:

 

SETTINGS.intro.topics.singer.btn.params.initialPosition

 

Like you guessed, I'm pretty sure you will need to build the SETTINGS object and then populate it with those values.

  • Like 3
Link to comment
Share on other sites

On 5/24/2017 at 9:42 AM, Robert Wildling said:

And maybe also, if it is in general a good idea to build up such a SETTINGS object, anyway? Or would there be better approaches for SPAs?

 

In general, I would say no. In a SPA, you usually build the DOM based on some data, but not as granular as your settings object. For example, look at the data object used in this demo. The DOM is constructed from 3 simple properties defined in each data object.

 

 

SPAs can be incredibly difficult to build and manage. I would recommend using a framework if you're new to SPA development. Some popular ones include AngularJS, Angular, Vue, React, and Polymer.

  • Like 1
Link to comment
Share on other sites

@Carl Thanks for your response!!! Always very helpful to get the assistance from a pro! Meanwhile, I externalized DOM elements that are needed more than once, into another small object, and it turns out that this structure helps a lot with other, previously not seen situation.

 

@OSUblake Thank you for your help! I am familiar with Angular and, since recently, VueJS. They are great, but they are there to handle business logic.

 

What I try to find is a way to handle "animation" logic. What I constantly encounter is that, upon loading a website, the DOM should be (not must) analysed first for all those elements that need to be handled by GSAP, in case I want to build consistent animation-rich UI. (Because, from what I learned, it is a speed optimisation, when I save the result of a "document.querySelection()" to a variable, so it can be accessed later in a faster manner, because the DOM doesn't need to be parsed again. It seems to be a bit like a "cache"... is that a very wrong understanding?).

 

Another thing I keep encountering is, that, depending on what has to be done in such an "app", there will always be some functions that exist in an anonymous name space, like this: (function(){...})();, which is a bit troublesome ( at least in my mind), because they need to call their own document.querySelector(), even though it might have already be done at some other place.

 

Therefore, I thought it might be a good idea to build an object, which holds all those DOM elements necessary for GSAP in its own global namespace, so each an every function throughout the application has/can access it. Adding all the parameters that are needed for an animation only seemed to be a logical next step. Such an object also helps to manage some other things like booleans, e.g. "isActive: true", a value that can be accessed from anywhere.

I'd like to see it as a kind of $root object, but only for animation-related things.

 

Also, when it comes to responsiveness, some things like  an object's "multiple" parameters (e.g. "topic: { params: { mobile: { [...] }, tablet: { [...] }, desktop: { [...] }}}) can be (re)assigned with an "assignParamsOnBreakpoint" or "reassignOnBreakpointChange" (for those, who like to resize the browser window) function, which I do with Harvey.js and turns out to work very nicely.

 

Of course, I have my doubts, if that is the proper way, so I wonder, if there is any information available on how to manage large animation projects. Just yesterday, I tried a new approach with data-attributes: all those elements that eventually will have a role within GSAP, get an attribute assigned like this: data-gsap="topic-button", data-gsap="logo" data-gsap-params="{fadeIn: {}, fadeOut: {}}". At the moment I like this approach, since it allows me to define a "params" object on a DOM element, which I cannot do as easily with e.g. OOCSS: "gsap  gsap-logo  gsap-logo--fade-in". 'gsap-logo--fade-in' is a class that, at some point, must be removed/replaced (unless, in this case, GSAP's reverse() function is used...). With data-attributes, i just yould assign 2 param attr: "data-gsap--fade-in="{ [...] }" and  "data-gsap--fade-out="{ [...] }".

 

Some more thoughts:

The consistent naming scheme (data-gsap) would probably help a lot to write a simple function that assigns all the found information to a SETTINGS object.

Just adding data-gsap attributes would automatically "make something work" without adding extra JS code... (well, sort of at least... not at this point...) 

 

That said, I – currently – like my SETTINGS object, since it, "by chance", more or less, turns out to be useful within other scenarios, like assigning eventListeners to clickable objects, which is not GSAP-related thingy by itself, but leads to call a function that initiates a TweenMax or a TimelineMax.

 

Is that all very confusing, what I just tried to explain and is going on in my mind? Or totally the wrong way? Or is it in general a usable solution, but could need some optimisation?

 

Any opinions would be greatly appreciated! Thanks a lot!

Link to comment
Share on other sites

Angular isn't for business logic. It's a framework for building apps based on the Model View Controller (MVC) and Model View ViewModel pattern (MVVM). Vue is the "V" in that pattern, the view (the user interface), which is where its name comes from, Vue = View. React would also be considered a view library. 

 

Simple, state based animations.

See the Pen 5d9d6fe688766b469f5d4db88ef069b2 by osublake (@osublake) on CodePen

 

 

6 hours ago, Robert Wildling said:

What I try to find is a way to handle "animation" logic. What I constantly encounter is that, upon loading a website, the DOM should be (not must) analysed first for all those elements that need to be handled by GSAP, in case I want to build consistent animation-rich UI. (Because, from what I learned, it is a speed optimisation, when I save the result of a "document.querySelection()" to a variable, so it can be accessed later in a faster manner, because the DOM doesn't need to be parsed again. It seems to be a bit like a "cache"... is that a very wrong understanding?).

 

You have the right idea. Parsing the DOM can be a performance killer, and caching stuff is much faster, but your objects aren't doing anything. Add some functions to your objects, and they can work with a particular context, so you won't have to call document.querySelection() again. And instead of using object literals for everything {}, use objects that you can create over and over again. 

 

Do that, and you can build Boring Boxes with everything contained within the object...

 

Here's a post where I briefly go over creating classes like that.

 

Link to comment
Share on other sites

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.

×