How to filter a repeater using multiple single checkboxes (Boolean data)

Hi all, this one seems like it should be straightforward, but I can not get it to work.

I have a repeater, connected to a dataset, and want build a filter using multiple single checkboxes (see image below). To clarify - the below example is NOT a multichoice checkbox, but rather nine single checkboxes stacked together.

Now I know I can use multichoice checkboxes, instead of numerous single checkboxes, but that orders the options alphabetically (with no ability to change that as far as I can tell) and that ordering doesn’t make sense for most of my filter categories.

To get around this, I’m trying the multiple single checkboxes approach. If I connect each checkbox to the dataset without code, each acts independently (meaning multiple selections are treated as AND rather than OR - which is what I desire).

First question I guess is, is there any simple code to make them OR, rather than AND?

I couldn’t find any, so instead have disconnected all of the checkboxes from the dataset and tried to connect it with code instead. The code I’ve found that most looked like it should do the job is posted below (this is all of the code on my page), but it does not work. As soon as I check either Hiking or Kayaking in the filter, everything in the repeater disappears. To clarify, I haven’t tried coding it for all checkboxes yet - I’ve just focused on two to keep it manageable until I see it is working.

Any help in getting this to work would be greatly appreciated and please let me know if you need any more info to assist. Thanks!

import wixData from 'wix-data';

$w.onReady (function () {
    $w('#hikingCheckbox').onChange(() => {
        updateFilter(); 
    })
    $w('#kayakingCheckbox').onChange(() => {
        updateFilter();
    })
});

function updateFilter () {
    const hiking = $w('#hikingCheckbox').checked;
    const kayaking = $w('#kayakingCheckbox').checked;

    let filter = wixData.filter();

    if (hiking) {
        filter = filter.eq('hiking', hiking);
    }

    if (kayaking) {
        filter = filter.eq('kayaking', kayaking);
    }

    $w('#articlesDataset').setFilter(filter);
}

Make sure you have connected the repeater to the CMS. It’s important to ensure that when you run a query to filter data from the database, the dataset ID is correct and matches what is defined in the CMS. You can verify this in your Wix editor and ensure that any IDs used in your code match those used in the database or dataset component.
I hope this works for you:

Thanks for your reply. My repeater is definitely connected to my CMS as you can see in this image:

Using the code in the video you linked did not work unfortunately, even when trying to connect it to just one of the checkboxes. It literally does nothing at all which I find really strange. The image below shows the preview with “Kayak” selected and non-kayak activities shown in the repeater.

Have I missed something? I feel like the problem might be that these are Boolean inputs and so the onReady function call to the “value” doesn’t really make sense? I tried substituting it for “checked”, but that also did not work. Any other ideas?

This is my code, after I added my element IDs - those being my database name (Articles dataset - for the record I also tried the dataset ID of articlesDataset and it made no difference), database field (kayakingCheckbox = ID in my dataset for the kayaking Boolean data), checkbox group ID (kayakCheckbox = ID of the single checkbox input for filtering kayak activities, and no it’s not meant to be kayakingCheckbox), and finally repeater ID (activityRepeater):

import wixData from 'wix-data';

const databaseName = 'Articles dataset';
const databaseField = 'kayakingCheckbox';

$w.onReady(function () {

    $w('#kayakCheckbox').onChange((event) => {
        const selectedBox = $w('#kayakCheckbox').value;
        addItemstoRepeater(selectedBox);
    })
});

function addItemstoRepeater(selectedOption = []) {

    let dataQuery = wixData.query(databaseName);

    if (selectedOption.length > 0) {
        dataQuery = dataQuery.hasSome(databaseField, selectedOption);
    }

    dataQuery
        .find()
        .then(results => {
            const filtereditemsReady = results.items;
            $w('#activityRepeater').data = filtereditemsReady;

        })
}

Hi @najmazahid, thanks for the offer, but I actually figured it out :slight_smile:

It took many iterations through Gemini and breaking down the code bit by bit to get it to work separately first and then making it go together, but I got there in the end.

For anyone interested in a solution (of sorts), I’ll post the code below and try my best to explain it in as much detail as I can. I say of sorts, because I ended up shifting away from Booleans (see below). I realise there may be cases where you do need them to be Booleans, in which case, I’m not sure this post will help you sorry, but there may be some building blocks to start from?

To provide an update on how things changed:

Firstly, I realised it wasn’t necessary to use multiple Boolean inputs in my case, but rather use the multi-checkbox, as it won’t actually be connected to the CMS and so I can order the labels and values as I like. A note on this step: make sure the “values” you assign the checkboxes are exactly the same (case sensitive) as the “values” of the “field” in your dataset that you will link it to with the code.

Secondly, I still wanted to be able to filter the repeater across more than one multiple checkbox input, so the code does include that capability.

Thirdly, once I figured out the code for filtering the repeater using multiple checkbox inputs, I realised that this code overrode the filter (only showing items with a specific value on a specific field) and sort (alphabetically) I had applied to the dataset connected to the repeater through the panel (not coded), so I needed to add code to make this happen again.

So here is the code, with as much details shown using the //text as I can think of to include. Note: I am not an experienced coder - amateur at best - so I may not have used correct terminology along the way, but hopefully it makes sense to the average person.

Hope this helps and happy to answer any questions!

import wixData from 'wix-data';

// Note: your Collection ID may not be the same as you your Database ID. To find your Collection ID, go into "Edit Collection Settings" of your collection.
const databaseName = 'Your Collection ID'; // Your Collection ID.
const difficultyField = 'Your Field ID #1'; // Field ID you will link your first checkbox input to. 
const activityField = 'Your Field ID #1'; //Field ID you will link your second checkbox input to.
//Consider changing the prefix (start) of the second and third const to better align with your FieldID name - note where you will need to change the references to them throughout the code. You can also add additional const lines if you wanted to add more inputs.

//The below code initially filters and sorts the repeater so that only items of a specific value on a specific field from the dataset are shown to users when the page loads, and the items are ordered alphabetically. 
$w.onReady(() => {
    const initialQuery = wixData.query(databaseName)
        .eq("yourFieldName", "yourValue") //Field name and specific value you are sorting the repeater by.
        .ascending("yourFieldName"); //Field name you are ordering the repeater by.

// The below code creates the on change event for when users check a box in the checkboxes.
    $w('#difficultyInput').onChange((event) => {
        filterItems(initialQuery);
    });

    $w('#activityInput').onChange((event) => {
        filterItems(initialQuery);
    });

    // The below code performs the initial fetch without filters.
    initialQuery.find()
        .then((results) => {
            $w('#yourRepeater').data = results.items; // Your repeater ID.
        })
        .catch((err) => {
            console.error(err);
        });
});

// The below code queries the dataset to filter the repeater.
function filterItems(initialQuery) {
    const selectedDifficulty = $w('#yourInputID1').value; //The element ID of your first checkbox input. 
    const selectedActivities = $w('#yourInputID2').value; ////The element ID of your second checkbox input.
// Consider changing the suffix (end) of both const to better align with your element IDs - note where you need to also change the references to them throughout the code.

    let query = initialQuery;

// The below code filters by the first checkbox input.
    if (selectedDifficulty.length > 0) {
        query = query.hasSome(difficultyField, selectedDifficulty);
    }

// The below code filters by the second checkbox input, with an AND condition (meaning that if two boxes in the checkbox are ticked, it will only return results that have both those values). If you don't want the AND condition, replace '[activity]' with 'selectedActivities' - noting that if you changed this const earlier, you would replace it with that. 
    if (selectedActivities.length > 0) {
        selectedActivities.forEach(activity => {
            query = query.hasSome(activityField, [activity]);
        });
    }

    query.find()
        .then(results => {
            $w('#yourRepeaterID').data = results.items; // Your repeater ID.
        })
        .catch(err => {
            console.error('Error fetching data:', err);
        });
}
1 Like