Subgroups in repeaters using multi-reference fields in wix

Question:
Creating Subgroups in repeaters using multi-reference fields in Wix

Product:
Wix Studio

What are you trying to achieve:
I have two datasets, one with a list of jobs and another with a list of job categories. The two are linked through a multi-reference field.

I am trying to use the category dataset as the headers for each item in my list repeater (there are 26 categories so 26 items in the repeater. Then I want each of the linked items which sit inside these categories from the Jobs dataset to be listed below, linking to their respective dynamic pages.

Can anyone help me in making this possible.

What have you already tried:
I’ve already tried a simple sort of the datasets to get them to play ball and i’ve played around with adding a table into the repeater to represent the Job dataset.

Additional information:
Here is a screenshot of what I’m trying to do:

@velogenius @wixexpertstudio Can anyone help with this one?

Hey Josh,

Can you provide screenshots (or dummy data) to show us how your databases are structured and linked?

@Pratham The current set up is very basic, two databases, one being categories and the other being jobs


The functionality that you want to implement requires a repeater nested within another repeater, which is currently not possible in Wix. However you can do this using custom code by linking radio buttons or selection tags inside the repeater.

If you’re not familiar with coding, then the best alternative would be to create a Title page for each category, and then have all the jobs for that category in a repeater on the title page, which you should be able to filter using a dataset.

Could you achieve the repeater inside a repeater affect with a table? Thats what I’ve done at the moment, just need to figure out if we can use code to drive the back end

Yes a table should work too, but we will have to use code to feed the repeaters as well as the tables inside of it. That’s because when I tried too replicate your setup on my end, I found out that a dataset does not return the multi-referenced field - without which we won’t have the data to work with. We will need to query the collection using code, which will give us a list of all the jobs under each category. I’ll create an example page and share it with you soon.

Here’s the demo page:

And here’s the code:

import wixData from 'wix-data';

$w.onReady(async function () {

    $w("#table").columns = [{
        "id": "Jobs",
        "dataPath": "title",
        "label": "Jobs",
        "width": 450,
        "visible": true,
        "type": "string",
        "linkPath": "link-jobs-title"
    }];

    $w("#repeater").onItemReady(($item, itemData, index) => {

        $item("#name").text = itemData.title;
        $item("#table").rows = itemData.Jobs_reference;

    });

    wixData.query("Categories")
        .include("Jobs_reference")
        .find()
        .then((results) => {

            $w('#repeater').data = results["_items"];

        }).catch((error) => {
            console.error(error);
        });

});

Now all you need to do is make sure if all the IDs, keys and values match your elements and DB contents. (:

2 Likes

Thanks for all your help, A few questions in implementing this:

  • Which dataset should the table be connected to?
  • By “Name” what element should I be connecting to?

You’re welcome!

In this we’re not connecting it via a dataset at all. We’re directly feeding data into the repeater using code.

Here’s a list of all the IDs and what are they connected to.

#repeater will be the ID of your repeater.

#table will be the ID of the tables inside the repeater.

#name is the ID of the category heading (which is above the tables - i.e. Transportation, Healthcare, etc…) inside the repeater.

Categories will be the ID of your Categories DB.

Jobs_reference will be the ID of the multi-reference field in the Categories DB that is linked to the Jobs DB.

link-jobs-title will be the dynamic (Title) page link path inside the Jobs DB.

Amazing, so I’ve made sure that all those are correct but does not seem to be linking still. I have another import data function on the page, would this be effecting it?

I also don’t yet have page links for these, could that be the problem on why it isn’t showing up?

You need to ensure that no element is connected via a dataset on the page.

I can’t know for sure unless I take a look at your page code. Please post it below.

Ok, so here is what it looks like:


Not the page, I’ll need to see the code - which is located in the panel at the bottom.
Copy-paste it here. I won’t be able to overwrite if it’s a screenshot.

I’ll need the whole page code in order to debug, not the screenshot of the same snippet.

In your code panel, press Ctrl + A then Ctrl + C, come here and press Ctrl + V.

From what it appears so far, you seem to have two import functions for the same module and probably two onReady functions as well. Which is why it’s probably not working.

You code will only work if you have no red underlines in it.

import wixData from 'wix-data';

let filterByTitle;
let debounceTimer;

$w.onReady(function () {
    $w("#searchBar").onKeyPress(function () {

        if (debounceTimer) {
            clearTimeout(debounceTimer);
            debounceTimer = undefined;
        }
        debounceTimer = setTimeout(() => {
            filter($w('#searchBar').value);
            checkKeyword()
            $w("#clearSearch").show();
        }, 100);
    });

    function filter(tutorials) {
        if (filterByTitle !== tutorials) {
            let newFilter = wixData.filter();

            if (tutorials)
                newFilter = newFilter.contains('title', tutorials);

            $w('#dataset2').setFilter(newFilter);

            filterByTitle = tutorials;
        }
    }

    //FILTER REPEATER WITH REPEATER ITEM
    $w('#dataset1').onReady(() => {
        $w('#repeater2').onItemReady(($item, itemData) => {

            //CREATE AN EMPTY ARRAY
            let arrKeyword = []

            $item('#button2').onClick(() => {

                $w('#repeater2').hide();

                //ADD THE ITEM'S TITLE TO THE ARRAY
                arrKeyword.push(itemData.title)

                console.log(arrKeyword)

                //FILTER DATASET WITH THE TITLE IN THE ARRAY
                $w('#dataset1').setFilter(wixData.filter().hasAll('title', arrKeyword));

            });
        });
    });

    //SHOW THE REPEATER ONLY WHEN THE ITEM IS FOUND
    function checkKeyword() {
        let searchKey = $w("#searchBar").value;

        wixData.query("Jobs")
            .contains("title", searchKey)
            .find()
            .then(result => {

                result.length > 0 ? $w("#repeater2").show() : $w("#repeater2").hide();

            });

    }

    //CLEAR FILTER
    $w("#clearSearch").onClick(() => {

        $w("#searchBar").value = undefined;
        $w("#clearSearch").hide();
        $w("#repeater2").hide();

        $w("#dataset1, #dataset2").setFilter(wixData.filter());
    });

});


import wixData from 'wix-data';

$w.onReady(async function () {

    $w("#table1").columns = [{
        "id": "Jobs",
        "dataPath": "title",
        "label": "Jobs",
        "width": 450,
        "visible": true,
        "type": "string",
        "linkPath": "link-jobs-title"
    }];

    $w("#repeater3").onItemReady(($item, itemData, index) => {

        $item("#name").text = itemData.title;
        $item("#table1").rows = itemData.Jobs_reference;

    });

    wixData.query("Categories")
        .include("Jobs_reference")
        .find()
        .then((results) => {

            $w('#repeater3').data = results["_items"];

        }).catch((error) => {
            console.error(error);
        });

});

I’ve combined the two onReady functions into one, it should work now - provided that all your IDs that I’d mentioned in the earlier post are perfect. And do remember to disconnect the repeater and the elements inside of it for this to work.

import wixData from 'wix-data';

let filterByTitle;
let debounceTimer;

$w.onReady(function () {
    $w("#searchBar").onKeyPress(function () {

        if (debounceTimer) {
            clearTimeout(debounceTimer);
            debounceTimer = undefined;
        }
        debounceTimer = setTimeout(() => {
            filter($w('#searchBar').value);
            checkKeyword()
            $w("#clearSearch").show();
        }, 100);
    });

    function filter(tutorials) {
        if (filterByTitle !== tutorials) {
            let newFilter = wixData.filter();

            if (tutorials)
                newFilter = newFilter.contains('title', tutorials);

            $w('#dataset2').setFilter(newFilter);

            filterByTitle = tutorials;
        }
    }

    //FILTER REPEATER WITH REPEATER ITEM
    $w('#dataset1').onReady(() => {
        $w('#repeater2').onItemReady(($item, itemData) => {

            //CREATE AN EMPTY ARRAY
            let arrKeyword = []

            $item('#button2').onClick(() => {

                $w('#repeater2').hide();

                //ADD THE ITEM'S TITLE TO THE ARRAY
                arrKeyword.push(itemData.title)

                console.log(arrKeyword)

                //FILTER DATASET WITH THE TITLE IN THE ARRAY
                $w('#dataset1').setFilter(wixData.filter().hasAll('title', arrKeyword));

            });
        });
    });

    //SHOW THE REPEATER ONLY WHEN THE ITEM IS FOUND
    function checkKeyword() {
        let searchKey = $w("#searchBar").value;

        wixData.query("Jobs")
            .contains("title", searchKey)
            .find()
            .then(result => {

                result.length > 0 ? $w("#repeater2").show() : $w("#repeater2").hide();

            });

    }

    //CLEAR FILTER
    $w("#clearSearch").onClick(() => {

        $w("#searchBar").value = undefined;
        $w("#clearSearch").hide();
        $w("#repeater2").hide();

        $w("#dataset1, #dataset2").setFilter(wixData.filter());
    });

    $w("#table1").columns = [{
        "id": "Jobs",
        "dataPath": "title",
        "label": "Jobs",
        "width": 450,
        "visible": true,
        "type": "string",
        "linkPath": "link-jobs-title"
    }];

    $w("#repeater3").onItemReady(($item, itemData, index) => {

        $item("#name").text = itemData.title;
        $item("#table1").rows = itemData.Jobs_reference;

    });

    wixData.query("Categories")
        .include("Jobs_reference")
        .find()
        .then((results) => {

            $w('#repeater3').data = results["_items"];

        }).catch((error) => {
            console.error(error);
        });

});

Hey Pratham. Thank you sooooo much for all the help you’ve given me, things are working super well and I’m looking to take this simple idea a whole lot further.

My only change I’m seeking to make to the code is when They click the box in the predictive search, it takes they straight to the page they clicked on, and when they click enter it filters the repeater and tables below for jobs which match only the phase searched.

Any chance I can get your contact details some way so I could potentially work with you in future if I decide to take this project further?

Hey Josh, you’re very welcome! (:

Sure, if you ever want to take this further, I’d love to collaborate. Please feel free to get in touch with me here: