Jump to content
Search Community

ScrollTrigger Refresh() doesn't affect items that's already passed the scroller-start

romain.gr test
Moderator Tag

Recommended Posts

Hi,

 

I have a little problem with the ScrollTrigger.refresh() function, actually it doesn't work as I was expecting to. As I mention in the title, when I use it, it doesn't affect items that has already passed the scroller-start marker.

 

So on the demo, I'm filtering a list of items, then I refresh the scrollTrigger and only the items after the start marker works.

 

Here is my scrollTrigger using create (on page load it works perfectly, the class is added to the items passed the start 'top 90%') :

$('.list-item').each(function(){
	var $this = $(this);
	
	ScrollTrigger.create({
		trigger: $this,
		markers: true,
		start: 'top 90%',
		onEnter: function(){
			console.log($this);
			$this.addClass('list-item--is-active');
		},
	});
	
});

Then I'm filtering my item using Mixitup (not sure this info is relevant) :

 

mixer = mixitup('.list', {
		selectors: {
				target: '.list-item'
		},
		animation: {
				duration: 0
		},
		controls: {
				live: true,
				toggleDefault: 'all',
				toggleLogic: 'or'
		},
		callbacks: {
				onMixEnd: function(state){}
		}

});

var listOfFilters = [];

$('.filters button').on('click', function(e){

		var thisFilter = $(this).data('filter-item');

		$(this).blur().toggleClass('btn--active');
		$('.list-item').removeClass('list-item--is-active');
	
		if(listOfFilters.includes(thisFilter)){
				const index = listOfFilters.indexOf(thisFilter);
				listOfFilters.splice(index, 1);
		} else {
				listOfFilters.push(thisFilter);
		}

		gsap.to('.list', {autoAlpha: 0, onComplete: function(){

				if(listOfFilters.length){
						mixer.filter(listOfFilters.toString());
				} else {
						mixer.show();
				}
				
				gsap.to('.list', {autoAlpha: 1});
				ScrollTrigger.refresh();
			
				// setTimeout(function(){
				// 	ScrollTrigger.refresh();
				// 	gsap.to('.list', {autoAlpha: 1});
				// }, 1000)

		}});


});

So on click on filter button (line 38 on codepen), I remove the .list-item--is-active class from all my .list-item (line 43);

 

Then on line 52 I use gsap to hide my list -> on the complete : make the filtering -> then  show the list and refresh the scrollTrigger.

 

The refresh should add the .list-item--is-active to the element at the top of the list, like it does on page load, but it doesn't, why?

 

So on the demo :

 

- load the page,

- scroll to the bottom

- scroll back to top

- then start filtering and unfiltering the list using the top buttons

 

You'll see that it doesn't work very well.

 

I'd like to know why and is it possible to make it work?

 

Thank you.

 

 

See the Pen poYyKyG by pen (@pen) on CodePen

Link to comment
Share on other sites

That actually isn't a bug - it's very intentional. The onEnter would only fire when the page initially loads because on subsequent refreshes (which could happen for many reasons, like a resize of the viewport or the address bar showing/hiding on a mobile device, etc.), you wouldn't want it to fire AGAIN each time. The onEnter is really supposed to only fire when something ENTERS the screen (from being off-screen). 

 

You can easily get the effect you want, though. There are many options in fact. One is to just loop through the triggers and fire the ones where the start value is less than the current scroll position: 

See the Pen gOErjyb?editors=1010 by GreenSock (@GreenSock) on CodePen

 

Or you could loop through the elements and use ScrollTrigger.isInViewport() to conditionally fire your logic and add the class that you want. There are probably other ways too but I don't want to overwhelm you. 🙂

 

Does that help? 

  • Like 1
Link to comment
Share on other sites

Hi Jack,

 

Thanks for your answer, it definitely works now but I have no idea how it has been done :

 

triggers.forEach((t) => t.start <= window.pageYOffset && t.vars.onEnter && t.vars.onEnter());

 

I understand nothing about this line, it's way too abstract for me, t.start, t.vars.onEnter and t.vars.onEnter(), what's that?

Could you break down this line, and explain each bits? So I can understand what it says exactly. Plus is there some documentation somewhere (on gsap forum, on the web or on the gsap website) explaining this whole issue, I guess I'm not the only one wanting to do that.

 

I checked the ScrollTrigger.isInViewport(), but it only check if the item is in view (or if x% of the item is in view), it would be great if we could pass start: 'top 90%', to it. It doesn't work in my case cause I want the class to be added when my item touches 90% of the viewport and not when my item is 90% (or 10% or whatever) in the viewport. I'm I wrong?

 

Thank you.

Link to comment
Share on other sites

6 hours ago, romain.gr said:

Could you break down this line, and explain each bits? So I can understand what it says exactly.

Sure, it's just a shorthand way of doing this: 

triggers.forEach((t) => {
  if (t.start <= window.pageYOffset && t.vars.onEnter) {
    t.vars.onEnter();
  }
});

The "&&" just means that if what comes before that is "truthy", it'll keep going and evaluate the next piece. If not, it just stops. So that line is basically saying "if the ScrollTrigger's start position is less than the current scroll position AND there's an onEnter defined on the ScrollTrigger's vars object, then call it. 

 

6 hours ago, romain.gr said:

I guess I'm not the only one wanting to do that.

I actually think you might be the first person to ask about this ever. I've been monitoring these forums for years and I can't recall anyone else getting confused about this behavior. Then again, my memory is getting worse 🤔

 

It's always a little tricky to do documentation. You can easily go too far in either direction (overly simplistic or WAY too much detail to where it's overwhelming for people to dig through). If we document every edge case question, the docs could get super intimidating. 

 

6 hours ago, romain.gr said:

I checked the ScrollTrigger.isInViewport(), but it only check if the item is in view (or if x% of the item is in view), it would be great if we could pass start: 'top 90%', to it. It doesn't work in my case cause I want the class to be added when my item touches 90% of the viewport and not when my item is 90% (or 10% or whatever) in the viewport. I'm I wrong?

Yeah, just stick with the solution I already offered. I didn't mean to confuse you by mentioning the other possible direction. 

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.
×
×
  • Create New...