Filters not working after the page is refreshed

Hi everyone,

I’m building a test website with EditorX and I’m having trouble with one of the pages. The live page can be found here . Everything works perfectly EXCEPT if I refresh the page. I really don’t understand what’s going on…

ABOUT THE PAGE:
All of the filter elements and all of the repeater elements on the page are populated programmatically.

THE ISSUE:

  1. The dropdown filters only work IF I access the page from the main menu for the first time or if I navigate to another page and come back. They do not work if I refresh the page.

  2. Additional note: This problem has been sitting there for about a week now. I think it’s important to mention that for almost a week that the problem only occurred during the day and magically disappeared after 5pm. I am quite new to coding, so I can’t be sure that the problem isn’t with my code but this is certainly strange. For the past few days though the problem is consistent throughout the day so I don’t know.

WHAT I’VE DONE:

  1. Refreshed my browser a million times, on my laptop and phone (Android). Tried on someone else’s phone. Same issue. Cleared my cache and browser data several times.

MY CODE:
I’m pasting almost everything here except for a few small functions (for formatting numbers and dates) since I’m really not sure what could be the problem…

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

$w.onReady(() => {
    //Populate dropdowns and initiate components
    initComps();
    //Initiate repeater
    initRepeater();
    //Show results based on search
    buildFiltersAndPopulateRepeater();
});

//FUNCTION #1 TO DEFINE REPEATER ELEMENTS
function initRepeater() {
    // REPEATER DATA FROM LEFT TO RIGHT
    repeater.onItemReady(($item, itemData, index) => {
        //DEPARTURE & ARRIVAL
        //Format "Departure" & "Arrival" in DD MMM YYYY, e.g. 2 Apr 2023.
        const departureDate = itemData.departure;
        const formattedDeparture = formatDate.format(departureDate);
        $item("#departureDate").text = String(formattedDeparture);

        const arrivalDate = itemData.arrival;
        const formattedArrival = formatDate.format(arrivalDate);
        $item("#arrivalDate").text = String(formattedArrival);

        //Count duration
        const duration = calcDuration(departureDate, arrivalDate);
        $item("#duration").text = String(`${duration} nights`);

        //YACHT & DESTINATIONS
        //Declare yacht name
        $item("#yachtName").text = `${itemData.yacht.title}`;

        //Add yacht link
        const yachtURL = `/luxury-liveaboard/${itemData.yacht.url}`;
        $item("#yachtName").onClick(function (event) {
            wixLocation.to(yachtURL);
        });

        //Declare destinations
        let dests = itemData.destinations;
        let destsArr = [];
        // Loop through no. of destinations
        for (let x = 0; x < dests.length; x++) {
            destsArr.push(dests[x].title);
        }
        $item("#destNames").text = destsArr.join(" - ");

        //ITINERARY & ROUTEte
        $item("#itineraryName").text = itemData.itinerary.title; //name
        $item("#embarkDisembark").text = String(itemData.itinerary.embarkationPort + " to " + itemData.itinerary.disembarkationPort);

        //PRICING & AVAILABILITY

        //Pricing & Discount Elements
        const startingPrice = itemData.cabinType1Price;
        const discAmt = itemData.discAmt;
        const discPercent = itemData.discPercentage;
        const charterOnly = itemData.charterOnly;
        const charterPrice = itemData.yacht.charterPrice;
        const charterPriceTotal = charterPrice * duration;

        const startPrice = $item("#startingPrice");
        const ribbonBox = $item("#ribbonBox");
        const ribbonText = $item("#ribbonText");
        const beforePrice = $item("#beforePrice");

        let discPrice;
        let ribbonMsg;

        const formattedPrice = String(USDollar.format(startingPrice));
        const formattedCharterPrice = String(USDollar.format(charterPriceTotal));

        //Remarks Elements
        const remarks = $item("#tripRemarks");
        const remarksVal = itemData.remarks;

        //AVAILABILITY & CAPACITY
        const yachtCap = itemData.yacht.capacity;

        //Constructor Function for Cabin types
        function CabinType(avail, male, female) {
            this.avail = avail;
            this.male = male;
            this.female = female;
            this.calcAvail = function (avail, male, female) {
                let total = avail + male + female;
                return total;
            };
            this.totalAvail = this.calcAvail(avail, male, female);
        }

        //Construct new cabins
        const cabinType1 = new CabinType(itemData.cabinType1Availability, itemData.cabinType1ShareMale, itemData.cabinType1ShareFemale);
        const cabinType2 = new CabinType(itemData.cabinType2Availability, itemData.cabinType2ShareMale, itemData.cabinType2ShareFemale);
        
        //REPEATER FUNCTION #1: CHECK AVAILABILITY
        const checkAvail = () => {
            const totalYachtAvail = cabinType1.totalAvail + cabinType2.totalAvail;
            if (!remarksVal) {
                if (totalYachtAvail === yachtCap) {
                    remarks.text = `Available for charter`;
                } else if (totalYachtAvail < 0.5 * yachtCap && totalYachtAvail > 0) {
                    remarks.text = `${totalYachtAvail} spots left`;
                } else if (totalYachtAvail === 0) {
                    soldOut();
                } else {
                    remarks.hide();
                }
            } else {
                if (remarksVal === "EMPTY") {
                    remarks.hide();
                } else {
                    remarks.text = remarksVal;
                }
            }
            return totalYachtAvail;
        };

        //REPEATER FUNCTION #2: CALCULATE DISCOUNT
        const calcDisc = (discType, basePrice, beforeVal) => {
            if (discType === discAmt) {
                discPrice = basePrice - discAmt;
                startPrice.text = String(USDollar.format(discPrice));
                ribbonMsg = `-${USDollar.format(discAmt)} off`;
            } else {
                discPrice = basePrice - (discPercent / 100) * basePrice;
                startPrice.text = String(USDollar.format(discPrice));
                ribbonMsg = `-${discPercent}% off`;
            }
            ribbonText.text = ribbonMsg.toUpperCase();
            ribbonBox.show();
            beforePrice.html = `<p>From ${beforeVal.strike()}</p>`;
        };

        //REPEATER FUNCTION #3: CLEAR IF SOLD OUT
        const soldOut = () => {
            startPrice.html = `<h3 style="color: #DA0000">SOLD OUT</h2>`;
            ribbonBox.hide();
            beforePrice.hide();
            remarks.hide();
            bookBtn.label = "Join Waitlist";
        };

        let curTotal = checkAvail();
        //IF TRIP IS NOT SOLD OUT
        if (curTotal > 0) {
            //If it's not a "charter only" trip
            if (!charterOnly) {
                //CONDITIONS FOR DISCOUNTS
                //If there's a discount amount
                if (discAmt) {
                    calcDisc(discAmt, startingPrice, formattedPrice);
                    //If there's a discount%
                } else if (discPercent) {
                    calcDisc(discPercent, startingPrice, formattedPrice);
                } else {
                    //If there's no discount
                    ribbonBox.hide();
                    startPrice.text = String(formattedPrice);
                }

                // If it's a charter only trip
            } else {
                if (discAmt) {
                    calcDisc(discAmt, charterPriceTotal, formattedCharterPrice);
                } else if (discPercent) {
                    calcDisc(discPercent, charterPriceTotal, formattedCharterPrice);
                } else {
                    //If no discount
                    startPrice.text = String(formattedCharterPrice);
                    //Charter only without a discount;
                    beforePrice.text = `Charter from`;
                    ribbonBox.hide();
                }
                if (!remarksVal) {
                    remarks.text = `Charter only`;
                } else {
                    if (remarksVal === "EMPTY") {
                        remarks.hide();
                    } else {
                        remarks.text = remarksVal;
                    }
                }
            }
            //IF TRIP IS SOLD OUT
        } else {
            soldOut();
        }

        //BUTTON ELEMENTS
        const bookBtn = $item("#bookBtn");
        const itinBtn = $item("#itinBtn");
        const btnLink = `/booking/${itemData.tripCode}`;
        const itinLink = `/itinerary/${itemData.itinerary.url}`;
        bookBtn.link = btnLink;
        bookBtn.target = "_blank";
        itinBtn.link = itinLink;
        itinBtn.target = "_blank";

    });
}

//FUNCTION #2 TO BUILD FILTERS AND POPULATE REPEATERS BASED ON FILTERS
async function buildFiltersAndPopulateRepeater() {
    let query = wixData.query("ScheduleRates");
    query = query.ascending("departure").include("yacht", "destinations", "itinerary");

    if (yachtFilter.value) {
        query = query.eq("yacht", yachtFilter.value);
    }

    if (destFilter.value) {
        query = query.hasSome("destinations", destFilter.value);
    }

    if (yearFilter.value && yearFilter.value != "0") {
        let firstDate = new Date(Number(yearFilter.value), 0);
        let lastDate = new Date(Number(yearFilter.value) + 1, 0);
        query = query.ge("departure", firstDate).lt("departure", lastDate);
    }

    repeater.data = await query.find().then((res) => {
        let hasNext = res.hasNext;
        let hasPrev = res.hasPrev;
        if (res.items.length > 0) {
            return res.items;
        } else {
            repeater.data = [];
        }
    });

}

//FUNCTION #3 TO INITIATE COMPONENTS
async function initComps() {
    populateDropdown(destDataset, destFilter, "destinations");
    populateDropdown(yachtsDataset, yachtFilter, "yacht");
    populateYears();
     //Allow filtering on change
    const filterBy = (filter) => {
        filter.onChange(() => {
            buildFiltersAndPopulateRepeater();
        });
    };
    filterBy(yachtFilter);
    filterBy(destFilter);
    filterBy(yearFilter);
    //Define reset function 
    const resetFilter = () => {
        yachtFilter.value = null;
        destFilter.value = null;
        yearFilter.value = null;
        buildFiltersAndPopulateRepeater();
    }

    resetBtn.onClick(() => {
        resetFilter();
    })

}

//FUNCTION #4 TO POPULATE DROPDOWNS
function populateDropdown(dataset, dropdown, type) {
    dataset.onReady(() => {
        dataset
            .getItems(0, Infinity)
            .then((res) => {
                let items = res.items;
                let arr = [{ label: "-", value: null }];
                for (let i = 0; i < items.length; i++) {
                    arr.push({ label: items[i].title, value: items[i]._id });
                }
                dropdown.options = arr;
                if (type.slice(-1) === "s") {
                    let str = type.slice(0, -1)
                    dropdown.placeholder = `Select a ${str}`;
                } else {
                    dropdown.placeholder = `Select a ${type}`;
                }
            })
    });
}

//FUNCTION #5 TO POPULATE YEARS DROPDOWN
function populateYears() {
        yearsDataset.onReady(() => {
            yearsDataset.getItems(0, Infinity).then((res) => {
                let trips = res.items;
                let years = [];
                let yearsArr = [{ label: "-", value: "0" }];
                for (let i = 0; i < trips.length; i++) {
                    let year = trips[i].departure.getFullYear();
                    if (!years.includes(year)) {
                        years.push(year);
                        yearsArr.push({ label: String(year), value: String(year) });
                        yearsArr.sort((a, b) => a.value.localeCompare(b.value));

                    }
                }
                yearsArr[0].value = null;
                yearFilter.options = yearsArr;
                yearFilter.placeholder = `Select a year`;
            })
        })

}

Thank you!

1 Like

You will notice in your console on refresh that you are getting an error…

Clicking on the file that the error is being thrown in, will take you here…

This is likely your issue and I suggest problem solving/debugging this code. My first guess is that this code is being fired too early but it’s hard to tell with all the code in the page. You will have to go through it to see.

1 Like

Hi Amanda. Thanks for your reply.

Actually I also contacted WIX Support and they pointed out that the problem comes from storing $w selectors and executable codes inside variables outside of an onReady function or any other functions.

The problem is immediately fixed once I moved all of these lines of code inside either an onReady function or another type of function.

This has been a great learning experience for me. Phew!

1 Like

Yup, that was my suspicion as well but wanted to give you the debugging knowledge so you would be able to learn how to solve the issues too. I’m so glad you figured it all out!

1 Like