Refresh Randomized Repeater On Page Load

Hi,
the goal is to have a repeater that randomly shows 3 items of a collection every time the page loads.

This is my code

import wixData from 'wix-data';
import wixLocation from 'wix-location';

$w.onReady(function () {

    // 1) get a random skip number
    let max = 46 - 3;
    let skip = Math.floor(Math.random() * max) + 1;

    // 2) query the database and get 3 random itmes
    wixData.query("B2BCatalog")
       .eq('isVisible',Boolean(true))
       .ascending("title")
       .skip(skip)
       .limit(3)
       .find()
       .then((results) => {
            let items = results.items;
            // 3) create a repeater data object from our retrieved data
            let itemData = [{
                    "_id": items[0]._id,
                    "text1": items[0].title,
                    "short": items[0].shortBio,
                    "durationLabel": items[0].durationLabel,
                    "dishImage": items[0].primaryImage,
                    "link": items[0]['link-virtual-team-building-activities-title']

                },
                {
                     "_id": items[1]._id,
                    "text1": items[1].title,
                    "short": items[1].shortBio,
                    "durationLabel": items[1].durationLabel,
                    "dishImage": items[1].primaryImage,
                    "link": items[1]['link-virtual-team-building-activities-title']
                },
                {
                     "_id": items[2]._id,
                    "text1": items[2].title,
                    "short": items[2].shortBio,
                    "durationLabel": items[2].durationLabel,
                    "dishImage": items[2].primaryImage,
                    "link": items[2]['link-virtual-team-building-activities-title']
                }
            ];
            console.log(itemData);
            // 4) set the repeater data property with our data object
            $w("#repeater2").data = itemData; // add data to our repeater 
        })
        .catch((error) => {
            let errorMsg = error.message;
            let code = error.code;
        });

    // 5) method to handle each repeated item
    $w("#repeater2").onItemReady(($w, itemData, index) => {
        // all we do here is set the repeated image from our data
        const repeatedText = $w("#text402");
        repeatedText.text = itemData.text1;

        const repeatedshortDesc = $w("#text337");
        repeatedshortDesc.text = itemData.short;

        const repeatedshortDurationLabel = $w("#image201");
        repeatedshortDurationLabel.src = itemData.durationLabel;

        const repeatedDishImage = $w("#image196");
        repeatedDishImage.src = itemData.dishImage;

        let linkToDynamicPage = itemData.link;
        $w('#button69').onClick(() => {
            wixLocation.to(linkToDynamicPage);
        });
    });
});

This works 90% of the times. The itemData object built with the items retrieved from the collection correctly populates the repeater.

Unfortunately, randomly this does not work. Meaning that from time to time while browsing, the query does not run, the itemData object is not populated therefore the repeater shows the placeholders.

I have a strong suspect that this depends on the query which sometimes returns the results when the page is already rendered. How can I prevent this? I tried with async/await but I don’t want to impact the page load time EVERY time the page loads because as I said 90% of the times the query executes in time.

Any idea how to prevent this?
@Yisrael (Wix) I followed your code in this post, I guess you could have a fast solution.
I would much appreciate your help.

Thanks!
Matteo

You should move the onItemReady() to the beginning of the page’s onReady() function. As stated in the documentation…
“Because setting a repeater’s data property triggers the onItemReady() callback to run, make sure you call onItemReady() before you set the data property. Failing to do so will mean that your callbacks are not triggered when you set the data property.”

Thanks for your prompt reply @yisrael-wix ! :slight_smile: unless I misinterpreted your message I simply moved the onItemReady() to the beginning as follows…but unfortunately the issue persists :frowning: Any other idea?

import wixData from 'wix-data';
import wixLocation from 'wix-location';

$w.onReady(function () {
     // Added at the beginning of the onReady
    $w("#repeater2").onItemReady(($w, itemData, index) => {
        // all we do here is set the repeated image from our data
        const repeatedText = $w("#text402");
        repeatedText.text = itemData.text1;

        const repeatedshortDesc = $w("#text337");
        repeatedshortDesc.text = itemData.short;

        const repeatedshortDurationLabel = $w("#image201");
        repeatedshortDurationLabel.src = itemData.durationLabel;

        const repeatedDishImage = $w("#image196");
        repeatedDishImage.src = itemData.dishImage;

        let linkToDynamicPage = itemData.link;
        $w('#button69').onClick(() => {
            wixLocation.to(linkToDynamicPage);
        });

        // you can do a whole lot more in this routine:
        // - handle other fields or elements
        // - add an onClick() handler
        // - handle selected repeat items
    });

    // 1) get a random skip number
    let max = 46 - 3;
    let skip = Math.floor(Math.random() * max) + 1;

    // 2) query the database and get 3 random itmes
    wixData.query("B2BCatalog")
        .eq('isVisible', Boolean(true))
        // .eq("isVisible", true)
        .ascending("title")
        .skip(skip)
        .limit(3)
        .find()
        .then((results) => {
            let items = results.items;
            // 3) create a repeater data object from our retrieved data
            let itemData = [{
                    "_id": items[0]._id,
                    "text1": items[0].title,
                    "short": items[0].shortBio,
                    "durationLabel": items[0].durationLabel,
                    "dishImage": items[0].primaryImage,
                    "link": items[0]['link-virtual-team-building-activities-title']

                },
                {
                    "_id": items[1]._id,
                    "text1": items[1].title,
                    "short": items[1].shortBio,
                    "durationLabel": items[1].durationLabel,
                    "dishImage": items[1].primaryImage,
                    "link": items[1]['link-virtual-team-building-activities-title']
                },
                {
                    "_id": items[2]._id,
                    "text1": items[2].title,
                    "short": items[2].shortBio,
                    "durationLabel": items[2].durationLabel,
                    "dishImage": items[2].primaryImage,
                    "link": items[2]['link-virtual-team-building-activities-title']
                }
            ];
            console.log(itemData);
            // 4) set the repeater data property with our data object
            $w("#repeater2").data = itemData; // add data to our repeater 
        })
        .catch((error) => {
            let errorMsg = error.message;
            let code = error.code;
        });

    // 5) method to handle each repeated item

});

I’m a potato head, missed this altogether…

Note that your onItemReady() function should be using the Repeated Item Scope as detailed in the documentation . You should be using $item and not $w.

You can simplify your code somewhat by directly setting the appropriate element property. For example:

Instead of this (note that I changed the code to use $item ):

const repeatedText = $item("#text402");
repeatedText.text = itemData.text1;

You want this (note that I also changed the code to use $item):

$item("#text402").text = itemData.text1;

Another thing, not sure if it causes a problem, but true is Boolean, you don’t need Boolean(true). There is no reason to “convert” true to Boolean.

You should also check the skip value with a console.log(‘skip’, skip); statement to ensure that the value of skip is greater than the number of items in the collection.

  1. Unfortunately did not change either with the Repeated Item scope :(((

import wixData from 'wix-data';
import wixLocation from 'wix-location';

$w.onReady(function () {
    $w("#repeater2").onItemReady(($item, itemData, index) => {
        // all we do here is set the repeated image from our data
        /*      const repeatedText = $w("#text402");
        repeatedText.text = itemData.text1;

        const repeatedshortDesc = $w("#text337");
        repeatedshortDesc.text = itemData.short;

        const repeatedshortDurationLabel = $w("#image201");
        repeatedshortDurationLabel.src = itemData.durationLabel;

        const repeatedDishImage = $w("#image196");
        repeatedDishImage.src = itemData.dishImage;
*/
        $item("#text402").text = itemData.text1;
        $item("#text337").text = itemData.short;
        $item("#image201").src = itemData.durationLabel;
        $item("#image196").src = itemData.dishImage;

        let linkToDynamicPage = itemData.link;
        $item('#button69').onClick(() => {
            wixLocation.to(linkToDynamicPage);
        });

        // you can do a whole lot more in this routine:
        // - handle other fields or elements
        // - add an onClick() handler
        // - handle selected repeat items
    });

    // 1) get a random skip number
    let max = 46 - 3;
    let skip = Math.floor(Math.random() * max) + 1;

    // 2) query the database and get 3 random itmes
    wixData.query("B2BCatalog")
        .eq('isVisible', Boolean(true))
        // .eq("isVisible", true)
        .ascending("title")
        .skip(skip)
        .limit(3)
        .find()
        .then((results) => {
            let items = results.items;
            // 3) create a repeater data object from our retrieved data
            let itemData = [{
                    "_id": items[0]._id,
                    "text1": items[0].title,
                    "short": items[0].shortBio,
                    "durationLabel": items[0].durationLabel,
                    "dishImage": items[0].primaryImage,
                    "link": items[0]['link-virtual-team-building-activities-title']

                },
                {
                    "_id": items[1]._id,
                    "text1": items[1].title,
                    "short": items[1].shortBio,
                    "durationLabel": items[1].durationLabel,
                    "dishImage": items[1].primaryImage,
                    "link": items[1]['link-virtual-team-building-activities-title']
                },
                {
                    "_id": items[2]._id,
                    "text1": items[2].title,
                    "short": items[2].shortBio,
                    "durationLabel": items[2].durationLabel,
                    "dishImage": items[2].primaryImage,
                    "link": items[2]['link-virtual-team-building-activities-title']
                }
            ];
            console.log("Nuovo: " + itemData);
            // 4) set the repeater data property with our data object
            $w("#repeater2").data = itemData; // add data to our repeater 
        })
        .catch((error) => {
            let errorMsg = error.message;
            let code = error.code;
        });

    // 5) method to handle each repeated item

});

On top of that if I remove Boolean(true) and use only

.eq('isVisible, true)

the query does not work at all.

What I am doing wrong?

Small typo, missing the closing tick mark after isVisible :

.eq('isVisible,true)

Perhaps no results, or fewer than 3, are returned from the query? That would of course cause a run-time error of undefined value. A console.log() statement would help. Did you try without the filter for isVisible? Does it make a difference?

Another possibility is that you have a problem with your data. Maybe you have empty items or blank fields in some of the DB collection items. Perhaps there are other issues with the data in the collection.