Add navigation buttons to repeater or layouter (slider mode)

Hello everyone!

Thank you so much for this solution! I’ve finally been able to make my first horizontal scrolling page :fire:

@jonathant i’m making an entire horizontal scrolling website. Is there a solution in order to switch from slide to slide with a hand touch (finger swipe) ? For example on the touch bar of a laptop or on tablettes and phones ?
It will improve the user experience and the navigation.

Thank you,

Bests regards,

Charlotte

I’m not aware of the solution for this but i think a workaround for it would be:

  1. Choose not to display the container Jonathan shared, that’s only in the smaller viewports (Tablet, mobile)
  2. Add another container/repeater again from scratch to these smaller viewports.
  3. Set it as Slider (do not display scroll bar)

This design by default should be touch sensitive but does not work with a mouse, hence the reason why I mentioned you should keep Jonathans solution for the larger viewports.

@jonathant I’m trying to recreate the same thing as your example with as a hero slider for my site. However, I’m finding that the scroll is not set to the full width of the image.

The test page for this can be found at https://www.clcorbin.co/blank-2

Also is there a cross fade animation option instead of sliding.

My code is below, any help would be greatly appreciated!

$w . onReady ( function () {

let repeater = $w ( ‘#repeater3’ );
let leftSliderBtn = $w ( ‘#leftSliderBtn’ );
let rightSliderBtn = $w ( ‘#rightSliderBtn’ );
let counter = 0 ;

rightSliderBtn . onClick (() => { 
    slideRight (); 
}) 
leftSliderBtn . onClick (() => { 
    slideLeft (); 
}) 

function autoSlide () {
slideRight ()
setTimeout ( autoSlide , 3000 );
}
autoSlide ()

function  slideRight () { 
    counter ++; 
    wixWindow . getBoundingRect () 
        . then (( windowSizeInfo ) => { 

let documentWidth = windowSizeInfo . document . width ;
let moveDistance = documentWidth * 0.65 ; // Container width

if ( counter >= 3 ) {
wixAnimations . timeline (). add ( repeater , { x : -( counter * moveDistance ), duration : 300 , easing : ‘easeOutSine’ }). play ()
. onComplete (() => {
wixAnimations . timeline (). add ( repeater , { x : 0 , duration : 0 , easing : ‘easeOutSine’ }). play ();
counter = 0 ;
})
} else {
wixAnimations . timeline (). add ( repeater , { x : -( counter * moveDistance ), duration : 300 , easing : ‘easeOutSine’ }). play ();
}
});
}

function slideLeft () {
counter --;
wixWindow . getBoundingRect ()
. then (( windowSizeInfo ) => {
let documentWidth = windowSizeInfo . document . width ;
let moveDistance = documentWidth * 1 ; // Container width

if ( counter < 0 ) {
wixAnimations . timeline (). add ( repeater , { x : ( repeater . data . length - 2 ) * - moveDistance , duration : 300 , easing : ‘easeOutSine’ }). play ();
counter = 3 ;
} else {
wixAnimations . timeline (). add ( repeater , { x : counter * - moveDistance , duration : 300 , easing : ‘easeOutSine’ }). play ();
}
});
}
});

Added additional lines for a different sized container width on each viewport
(taken from another example Jon. made)

Not an expert so best to verify but works fine on all viewports.


// API Reference: https://www.wix.com/velo/reference/api-overview/introduction
// “Hello, World!” Example: https://learn-code.wix.com/en/article/1-hello-world

import wixAnimations from 'wix-animations';
import wixWindow from 'wix-window';

$w.onReady(function () {

 let repeater = $w('#repeaterId');
 let leftSliderBtn = $w('#leftSliderBtnId');
 let rightSliderBtn = $w('#rightSliderBtnId');
 let counter = 0;

    rightSliderBtn.onClick(() => {
        slideRight();
    })
    leftSliderBtn.onClick(() => {
        slideLeft();
    })

 function slideRight() {
        counter++;
        wixWindow.getBoundingRect()
            .then((windowSizeInfo) => {
 let windowWidth = windowSizeInfo.window.width;               
 let documentWidth = windowSizeInfo.document.width;
 let moveDistance = documentWidth;
  if (windowWidth > 1400) {
    moveDistance = documentWidth * 0.41; // Desktop 1 Container width
   } else if (windowWidth >= 1001) {
    moveDistance = documentWidth * 0.45; // Desktop 2 Container width
   } else if (windowWidth >= 751) {
    moveDistance = documentWidth * 0.6; // Tablet container width
   } else if (windowWidth <= 750) {
    moveDistance = documentWidth * 0.8; // Mobile container width
   }

 if (counter >= 3) {
                    wixAnimations.timeline().add(repeater, { x: -(counter * moveDistance), duration: 500, easing: 'easeOutSine' }).play()
                        .onComplete(() => {
                            wixAnimations.timeline().add(repeater, { x: 0, duration: 0, easing: 'easeOutSine' }).play();
                            counter = 0;
                        })
                } else {
                    wixAnimations.timeline().add(repeater, { x: -(counter * moveDistance), duration: 500, easing: 'easeOutSine' }).play();
                }
            });
    }
 function slideLeft() {
        counter--;
        wixWindow.getBoundingRect()
            .then((windowSizeInfo) => {
 let windowWidth = windowSizeInfo.window.width;               
 let documentWidth = windowSizeInfo.document.width;
 let moveDistance = documentWidth;
  if (windowWidth > 1400) {
    moveDistance = documentWidth * 0.41; // Desktop 1 Container width
   } else if (windowWidth >= 1001) {
    moveDistance = documentWidth * 0.45; // Desktop 2 Container width
   } else if (windowWidth >= 751) {
    moveDistance = documentWidth * 0.6; // Tablet container width
   } else if (windowWidth <= 750) {
    moveDistance = documentWidth * 0.8; // Mobile container width
   }

 if (counter < 0) {
                    wixAnimations.timeline().add(repeater, { x: (repeater.data.length - 1) * -moveDistance, duration: 300, easing: 'easeOutSine' }).play();
                    counter = 3;
                } else {
                    wixAnimations.timeline().add(repeater, { x: counter * -moveDistance, duration: 300, easing: 'easeOutSine' }).play();
                }
            });
    }
});

Thank you all, and particularly, Jonathan, for this great solution.

@pneumaspace-au how did you solve the issue with the RIGHT button? I am facing a similar problem. It works until it reaches the 4th item, but after that it gets lost. The left button works fine.

I am using the same original code posted by Jonathan, with 4 items, and also 4 items in the collection.

Thank you in advance.

Hi, thank you Jonathan for your grate work. I now I’m little late to this post but I have one more question:

Is there a way to set up the size by a fix number like 500px? So the container is at 500px and not at 65%.

Do someone have a solution??? @ Tenessee Vogel , @jonathant ?

Hey @stschuele , you can simply change the “moveDistance” to 500 or any amount of pixels you want it to move. I calculated the % in order to make it responsive :slightly_smiling_face:

AAhhh thank you Jonathan it works!! I’ve also got a good solution with the new Layouter Slides mode cause its better for breakpoint and touch displays. The problem with that is, by clicking the next buttons you slide threw the whole list if you have more than one Item per raw. Not the best option. If you have the ability to set up to slide one Item at ones wether if there are more in a row like in this velo example, that would be great.

But thanks for your code! I think depending on what you work on, it is the better solution.

Hello everyone,
This is very close to a problem I have been trying to solve.

I want to do the same thing as being discussed above, however I want to do it in a Vertical repeater rather than a Horizontal repeater as discussed above.

What I am trying to do is create a scrollable menu with text boxes in the repeater. Each text box will be linked to the opacity of an image in a container next to it. Also I want to make it so that any text box that is currently highlighted or is in the active position triggers the hover effect the text to make it larger whilst also triggering the hover effect on the image brining it’s opacity to 100%

Most importantly though I’d just like the buttons to start working but I just can’t figure it out. Can anyone tell me how to modify the code suggested by Johnathan to work for this please?

Thank you in advance!

For some reason I can’t attach an image. But is kind of like

                 Up  Button 

Image. Text 1
Text 2
Test 3
… all the way to Text 12
Down Button

Hey jonathant!

I tried this solution

import wixAnimations from 'wix-animations';
import wixWindow from 'wix-window';

$w.onReady(function () {

 let repeater = $w('#repeater4');
 let leftSliderBtn = $w('#leftSliderBtn');
 let rightSliderBtn = $w('#rightSliderBtn');
 let counter = 0;

    rightSliderBtn.onClick(() => {
        slideRight();
    })
    leftSliderBtn.onClick(() => {
        slideLeft();
    })

 function slideRight() {
        counter++;
        wixWindow.getBoundingRect()
            .then((windowSizeInfo) => {
 let documentWidth = windowSizeInfo.document.width - (windowSizeInfo.document.width * 0.047);
 let moveDistance = documentWidth * 0.65; // Container width

 if (counter > 3) {
                    wixAnimations.timeline().add(repeater, { x: -(counter * moveDistance), duration: 300, easing: 'easeOutSine' }).play()
                } else {
                    wixAnimations.timeline().add(repeater, { x: -(counter * moveDistance), duration: 300, easing: 'easeOutSine' }).play();
                }
            });
    }

 function slideLeft() {
        counter--;
        wixWindow.getBoundingRect()
            .then((windowSizeInfo) => {
 let documentWidth = windowSizeInfo.document.width - (windowSizeInfo.document.width * 0.047);
 let moveDistance = documentWidth * 0.65; // Container width

 if (counter < 0) {
                    wixAnimations.timeline().add(repeater, { x: (repeater.data.length - 1) * -moveDistance, duration: 300, easing: 'easeOutSine' }).play();
                    counter = 3;
                } else {
                    wixAnimations.timeline().add(repeater, { x: counter * -moveDistance, duration: 300, easing: 'easeOutSine' }).play();
                }
            });
    }
});

I’m facing a problem that, when I click on the navigation button, my repeater carousel doesn’t show the content that slide in the screen. It’s like my content doesn’t exist. Could you help me?

screenshot below

Hey!
From first glance it looks like you’re moving the wrong element, but it’s hard to tell from screenshots.
Mind sharing the url to your website?

Sure!
https://amandamoraesadvsp.wixstudio.com/my-site-4?rc=test-site

Thanks
I see that you used a Slider layout, but unfortunately the code solution doesn’t work well with the Slider layout.
You’ll need to choose which behavior you prefer. Also, you can choose to have an arrow navigation on Desktop and to disable to the code on Mobile and use Slider.
Anyway, you need to change the layout to “Cards”
Here’s a library I created with the Asset, so you can just add it to the stage

@JonathanT Thanks for this detailed solution.

I’m trying to implement the same solution but with a different setup: I have a repeater connected to a dataset. I want to display three items at the same time on screen. On clicking the next and previous buttons, it should move one card over. But it’s moving the entire set out of view after two clicks. Additionally, I can’t hardcode the item count as it can change over time. But for now, there are 20 items in the set being displayed.

I’ve set it up as a repeated with Cards, the width set to 660% to show three cards at a time on screen.

import wixAnimations from 'wix-animations';
import wixWindow from 'wix-window';

$w.onReady(function () {

 let repeater = $w('#repeater18');
 let leftSliderBtn = $w('#leftSlide');
 let rightSliderBtn = $w('#rightSlide');
 let counter = 0;
 let maxItems = 20;

    rightSliderBtn.onClick(() => {
        slideRight();
    })
    leftSliderBtn.onClick(() => {
        slideLeft();
    })

 function slideRight() {
        counter++;
        wixWindow.getBoundingRect()
            .then((windowSizeInfo) => {
 let documentWidth = windowSizeInfo.document.width;
 let moveDistance = documentWidth * 0.33; // Container width
 console.log(moveDistance);

 if (counter > 19) {
                    wixAnimations.timeline().add(repeater, { x: -(counter * moveDistance), duration: 300, easing: 'easeOutSine' }).play()
                } else {
                    wixAnimations.timeline().add(repeater, { x: -(counter * moveDistance), duration: 300, easing: 'easeOutSine' }).play();
                }
            });
			console.log("Counter :"+counter);
    }

 function slideLeft() {
        counter--;
        wixWindow.getBoundingRect()
            .then((windowSizeInfo) => {
 let documentWidth = windowSizeInfo.document.width;
 let moveDistance = documentWidth * 0.33; // Container width
 console.log(moveDistance);

 if (counter < 0) {
                    wixAnimations.timeline().add(repeater, { x: (repeater.data.length - 1) * -moveDistance, duration: 300, easing: 'easeOutSine' }).play();
                    counter = 19;
                } else {
                    wixAnimations.timeline().add(repeater, { x: counter * -moveDistance, duration: 300, easing: 'easeOutSine' }).play();
                }
            });
			console.log("Counter :"+counter); 
	}
});

Here’s the preview link for the site: https://anil7263.wixstudio.com/movementology-clinic?rc=test-site

It’s the second carousel in the Patients Journey section.

Any help would be appreciated.

Thanks