Dynamic Slideshow using Dataset

I saw a request recently for a repeater to be able to manage a slide show or a repeater to perform as a slide show.

None of these options is trivial if you try to use the $w.Repeater or $w.Slideshow APIs. Using them is probably a little bit of over kill anyway when all you want to do is change a single container and some key property elements using data from a data set.

Here is one approach.

Step 1:

Create your slideshow data collection and populate it with whatever you want in your slide show.

Then in the Wix Editor connect
up the datacollection using a dataset connector. We will name the dataset
ā€˜#slideContentā€™. We can adjust the number of items per page depending on the number of elements we are showing.

Step 2:


Create the baseline element with the property elements that you want. So for this example we will use a $w.ColumnStrip. The columnStrip will have a single $w.Text element for an image title and we will use the $w.ColumnStrip background image to render an image in our slider.

Step 3:

Clone the Strip by right clicking the
$w.ColumnStrip element and selecting ā€œDuplicateā€. Now name the $w.ColumnStrip and the $w.Text elements something
that makes sense for your site.
I have used #columnStrip1 which contains #title1, and #columnStrip2 which contains #title2. Make sure that the two $w.ColumnStrips overlap each other (one is superimposed on the other). We will use these to create the slide show effect.

Step 4:


Create a slide change control to manage slide transition. I did this using a $w.Box that slightly overlaps the $w.ColumnStrip elements. This prevents the editor from adding the controls as children of the top most $w.ColumnStrip which we donā€™t want.
Make the $w.Box background transparent by setting the opacity to 0.
I chose an arrow design $w.VectorImage for the left and right arrows and named the elements #left and #right.

Step 5:

We need to wire up the arrows for our controls to move the slides left and right. You can do this in two ways. Firstly you can add onClick() handlers into the $w.onReady() function override OR you can bind the element via its property page. I chose the latter. Which results in the Wix Editor adding a function hook into the code page for you

external function right_click()

Step 6:

Now we can add some code to the page to create our SlideShow:


let isOdd = true;

$w.onReady(function () {
// Make sure our slide data is loaded before we try to load up our 
// first slide
    $w('#slideContent').onReady(() => {
        showNewItem($w('#slideContent').getCurrentItem());
    });
});

/*

    function: showNextItem
    description: Uses data from our data set to populate the 
                 next slide and when loaded swaps it with the 
                 one currently visible
    arguments:   item - the database record
                 direction - which way to animate our slide
*/
function showNewItem(item, direction) {
 if (item && item['title'] && item['photo']) {
 let nextSlide = getNextStrip();
 let strip = nextSlide[0];
 let title = nextSlide[1];
        strip.background.src = item['photo'];
        title.text = item['title'];
        swapSlides(direction);
    }
}

/*
     function: getNextStrip     
     description: Simple toggle function to select the elements we
                  need to populate for the next slide. The 'isOdd'
                  property is used to choose which elements we are 
                  interested in. It gets toggled before we exit.
     arguments:   none
*/
function getNextStrip() {
 let result = [];
 if (isOdd) {
    result.push($w('#columnStrip1'));
    result.push($w('#title1'));
 } else {
    result.push($w('#columnStrip2'));
    result.push($w('#title2'));
 }
 // Toggle the element selector
 isOdd = !isOdd;
 return result; 
}

/*
    Function: swapSlides
    Description: This function performs the slide show rendering
                 It makes use of the fact that effects are performed
                 using Promises and collects the effect promises
                 show() and hide() in a super promise using the all()
                 function. Direction is flowed down to the show and hide
                 methods which control animation
    Arguments:   direction - either 'left' or 'right'
*/
function swapSlides(direction) {
 let keepMyPromise = null;
 if (isOdd) {
        keepMyPromise = Promise.all(
            [
                hide($w('#columnStrip1'), direction),
                show($w('#columnStrip2'), direction)
            ]);
    } else {
        keepMyPromise = Promise.all(
            [
                show($w('#columnStrip1'), direction),
                hide($w('#columnStrip2'), direction)
            ]);
    }
 // Returns the Promise we created in case the calling function 
 // has something else to do after
 return keepMyPromise;
}

/*
    Function: hide
    Description: Creates a simple overlay on the normal $w.HiddenMixIn
                 API to apply Effect filters to the hide() function
    Arguments: element - the $w() element that we are hiding
               direction - 'left' or 'right' for slide egress direction
*/
function hide(element, direction) {
 let slideEffect = {
 "direction":    'right'
    };
 if (direction === 'right') {
        slideEffect.direction = 'left';
    }
 // Note we are using 'fade' here. It was originally 'slide' but the 
 // effect was not a good one if you want to use slide then remove
 // the fade and uncomment out this code:
 // return element.hide('slide', slideEffect);
 return element.hide('fade');
}

/*     Function: hide     
       Description: Creates a simple overlay on the normal 
                    $w.HiddenMixIn API to apply Effect filters 
                    to the hide() function     
       Arguments: element - the $w() element that we are showing
                  direction - 'left' or 'right' for slide egress 
                               direction
*/
function show(element, direction) {
 let slideEffect = {
 "direction":    'left'
    };
 if (direction === 'left') {
        slideEffect.direction = 'right';
    }
 return element.show('slide', slideEffect);
}
 
/*
 ****** Element handler functions

     Function:  right_click
     Description: fires when the right $w.VectorImage is clicked.
                  Used to advance the slide show to the right by 
                  using the dataset $w('#slideContent') next() function
                  or resetting the dataset index to 0 if we have reached 
                  the end of the data set. This creates a circular 
                  slide effect.
     Arguments:   event - the event object associated with the click
                  $w - the page scope variable for our element management
     Returns:     a promise that should resolve to the next item from 
                  the data set which is ".then()" passed to our 
                  showNewItem function where the slide show effect happens!
 */
export function right_click(event, $w) {
   let dataset = $w('#slideContent'); 
   let keepMyPromise = null;
   if (dataset.getCurrentItemIndex() === dataset.getTotalCount() - 1) {
      // We need to reset to the start of the slide show         
      keepMyPromise = dataset.setCurrentItemIndex(0)
      .then(() => { 
         return Promise.resolve(dataset.getCurrentItem()); 
      }); 
   } else { 
     // Get the next item
     keepMyPromise = dataset.next(); 
   }
     
   return keepMyPromise         
      .then((newItem) => { 
         showNewItem(newItem, 'right'); 
      });
} 

/*  
    Function:  right_click      
    Description: fires when the right $w.VectorImage is clicked.
                 Used to advance the slide show to the right by 
                 using the dataset $w('#slideContent') previous() 
                 function or resetting the dataset index to the end of 
                 the dataset if we have reached the beginning of the
                 dataset. This creates a reverse circular slideshow effect.      
    Arguments:   event - the event object associated with the click
                 $w - the page scope variable for our element management
    Returns:     a promise that should resolve to the next item from
                 the data set which is ".then()" passed to our
                 showNewItem function where the slide show effect happens!
*/
export function left_click(event, $w) {
 let dataset = $w('#slideContent');
 
 let keepMyPromise = null;
 if (dataset.getCurrentItemIndex() === 0) {
 // We need to reset to the start of the slide show
        keepMyPromise = dataset.setCurrentItemIndex(dataset.getTotalCount() - 1)
            .then(() => {
 return Promise.resolve(dataset.getCurrentItem());
            });
    } else {
 // Get the next item
        keepMyPromise = dataset.previous();
    }
 return keepMyPromise
        .then((newItem) => {
            showNewItem(newItem, 'left');
        });
 
}

I hope some of you find this useful.

Steve

4 Likes

thanks for the ideas and for the excellent documentation

You are welcome!

Thank you so much, you donā€™t know what you did for me.

hey stcroppe, I made soomethign very similar for a client but couldnā€™t get past the ā€˜slideā€™ transition effect problem. I just tried your code (which is excellent by the way) but it looks like you ran into something similar. Do you know of any way to stop the scroll bar at the bottom of the page from popping up when you slide a strip off screen?

Hi Matt:

Im not sure exactly what you are experiencing.

I did have problems with getting the slide effect to work. I think that your may be using a slide show control?

Because the initial target for this was a mobile device and wix doesnā€™t support mobile devices I used an element swap method using show and hide effects to get a sliding effect. The way I avoided what you may be experiencing was to hide the displayed ā€˜slideā€™ using a fade effect while showing the replacement slide using a fly in effect. I also played with the effect timings.

I know Iā€™m late to the party here but Iā€™m trying to apply the same methodology youā€™re saying to do except on 4 total columns at a time, and loading 1 at a time instead of all 4 again for my dynamic slideshow.

Iā€™d like to also note that I did everything you suggested step by step and have to say Iā€™m very proud of myself in accomplishing that and making it work so far, thank you very much for that :smiley:

Thank you very much for taking the time to share this. Itā€™s working really well to show my featured blog posts. Iā€™d really appreciate it if you could tell me how to create a strip column that is less than the full page width.

Thank you stcroppe - a massive help.

Slight tweaks to swapSlides() makes the slide effect work better.

The incoming slide has to slide in from the opposite side (counter-intuitively), and a small delay leaves a blank space between the slides.

function swapSlides(direction) {
 let keepMyPromise = null;
 var opposite = "right"
 if (direction === "right") {
    opposite = "left";
 }
 if (isOdd) {
        keepMyPromise = Promise.all(
            [
                hide($w('#columnStrip1'), direction),
                setTimeout(function() {
                    show($w('#columnStrip2'), opposite)
                }, 500)
 
            ]);
    } else {
        keepMyPromise = Promise.all(
            [
 
                hide($w('#columnStrip2'), direction),
                setTimeout(function() {
                    show($w('#columnStrip1'), opposite)
                }, 500)
            ]);
    }
 // Returns the Promise we created in case the calling function 
 // has something else to do after
 return keepMyPromise;
}
1 Like

anyone can help me? i try to do the same steps but it doesnā€™t work. The slider display only the first slide without the cursor and it donā€™t go on :frowning:

Perhaps share a link to your page?

You can do this much more simply: https://www.wix.com/velo/example/dynamic-slideshow

The problem with the one linked is you have to know in advance how many rows your dataset will contain as you cannot add slides dynamically on that one. I think the idea in the op is that you donā€™t need a const number of slides;