CMS Filter Works, but Dynamic Repeater Numbers Are Incorrect

Hi everyone,

I’m currently facing an issue with my Wix Studio publication page and would appreciate some help.

I have a publication page with two dropdown filters (e.g. Type of Publication and Year of Publication) connected to a CMS collection. The page also contains a repeater with dynamic numbering for the publications.

The filtering itself works correctly, but the dynamic numbers in the repeater do not sync properly with the dropdown filters.

For example, before filtering, the publications are numbered:

1, 2, 3, 4, 5, 6, 7, 8…

After selecting a filter, the results may become:

8, 2, 3, 4, 5…

Instead of resetting the numbering based on the filtered results:

1, 2, 3, 4, 5…

I would like the numbering to automatically restart from 1 whenever either dropdown filter is changed.

I’m using a CMS dataset, two dropdowns, and a repeater.

Has anyone experienced a similar issue or know the best way to synchronize the repeater’s dynamic numbering with the filtered dataset?

Any advice or example code would be greatly appreciated. Thank you!

Here’s our code:

import wixData from “wix-data”;

let filterRequestId = 0; // guards against out-of-order responses

$w.onReady(() => {

$w(“#dataset1”).onReady(() => {

updateFilteredCount();

});

// Fetch the grand total ONCE on page load — this never changes

// based on filters, so it doesn’t need to re-run on every dropdown change.

wixData.query(“Import570”)

.count()

.then((totalCount) => {

  $w("#text66").text = \`${totalCount}\`;

})

.**catch**((err) => console.error("count query failed:", err));

$w(“#repeater2”).onItemReady(($item, itemData, index) => {

// Single source of truth for row numbering — fires automatically

// whenever the repeater's connected dataset items change.

**const** rowNumber = index + 1;

$item("#text45").text = \`${rowNumber}\`;

$item("#text67").text = \`${rowNumber}\`;



**if** (!itemData.venue) {

  $item("#text61").collapse();

} **else** {

  $item("#text61").expand();

}

});

$w(“#dropdown1”).onChange(() => applyFilters());

$w(“#dropdown2”).onChange(() => applyFilters());

});

function applyFilters() {

const type = $w(“#dropdown1”).value;

const year = $w(“#dropdown2”).value;

// Prevent stacking multiple filter changes while one is still in flight

$w(“#dropdown1”).disable();

$w(“#dropdown2”).disable();

let filter = wixData.filter();

if (type && type !== “RESET_ALL”) {

filter = filter.eq("type", type);

}

if (year && year !== “RESET_ALL”) {

filter = filter.eq("year", Number(year));

}

// Bump the token for this request. Only the response matching

// the CURRENT token is allowed to update the UI — any earlier,

// slower request that resolves late gets ignored.

const thisRequestId = ++filterRequestId;

$w(“#dataset1”)

.setFilter(filter)

.then(() => {

  **if** (thisRequestId !== filterRequestId) {

    // A newer filter request has since been made — discard this stale result.

    **return**;

  }

  updateFilteredCount();

  console.log("Dataset filtered and order updated.");

})

.**catch**((err) => console.error("setFilter failed:", err))

.**finally**(() => {

  $w("#dropdown1").enable();

  $w("#dropdown2").enable();

});

}

function updateFilteredCount() {

const filteredCount = $w(“#dataset1”).getTotalCount();

$w(“#text65”).text = `${filteredCount}`;

}

The issue is caused by onItemReady(). It only runs when a repeater item is first created. If filtering retains an existing CMS item, Wix may reuse that repeater item, so it keeps its previous number. Wix recommends forEachItem() when updating existing repeater items.

function refreshRepeaterItems() {
    $w("#repeater2").forEachItem(($item, itemData, index) => {
        updateRepeaterItem($item, itemData, index);
    });
}```

Is this the new code that i should input??:

import wixData from “wix-data”;

let filterRequestId = 0; // guards against out-of-order responses

$w.onReady(() => {
$w(“#dataset1”).onReady(() => {
refreshRepeaterItems();
updateFilteredCount();
});

// Fetch the grand total ONCE on page load
wixData.query(“Import570”)
.count()
.then((totalCount) => {
$w(“#text66”).text = ${totalCount};
})
.catch((err) => console.error(“count query failed:”, err));

// Still needed for items created for the FIRST time
// (e.g. initial load, or repeater growing to show more items)
$w(“#repeater2”).onItemReady(($item, itemData, index) => {
updateRepeaterItem($item, itemData, index);
});

$w(“#dropdown1”).onChange(() => applyFilters());
$w(“#dropdown2”).onChange(() => applyFilters());
});

function applyFilters() {
const type = $w(“#dropdown1”).value;
const year = $w(“#dropdown2”).value;

$w(“#dropdown1”).disable();
$w(“#dropdown2”).disable();

let filter = wixData.filter();

if (type && type !== “RESET_ALL”) {
filter = filter.eq(“type”, type);
}
if (year && year !== “RESET_ALL”) {
filter = filter.eq(“year”, Number(year));
}

const thisRequestId = ++filterRequestId;

$w(“#dataset1”)
.setFilter(filter)
.then(() => {
if (thisRequestId !== filterRequestId) return; // stale, discard

  // Forces every CURRENTLY RENDERED item (reused or new)
  // to get its index/text corrected — fixes the reuse bug.
  refreshRepeaterItems();
  updateFilteredCount();
  console.log("Dataset filtered and order updated.");
})
.catch((err) => console.error("setFilter failed:", err))
.finally(() => {
  $w("#dropdown1").enable();
  $w("#dropdown2").enable();
});

}

// Single place that defines what a “row” looks like.
// Used by BOTH onItemReady (new containers) and forEachItem (reused containers).
function updateRepeaterItem($item, itemData, index) {
const rowNumber = index + 1;
$item(“#text45”).text = ${rowNumber};
$item(“#text67”).text = ${rowNumber};

if (!itemData.venue) {
$item(“#text61”).collapse();
} else {
$item(“#text61”).expand();
}
}

function refreshRepeaterItems() {
$w(“#repeater2”).forEachItem(($item, itemData, index) => {
updateRepeaterItem($item, itemData, index);
});
}

function updateFilteredCount() {
const filteredCount = $w(“#dataset1”).getTotalCount();
$w(“#text65”).text = ${filteredCount};
}

it makes it easier to read code if you use the Preformatted Text

import wixData from “wix-data”;

let filterRequestId = 0; // guards against out-of-order responses

$w.onReady(() => {
$w(“#dataset1”).onReady(() => {
refreshRepeaterItems();
updateFilteredCount();
});

// Fetch the grand total ONCE on page load
wixData.query(“Import570”)
.count()
.then((totalCount) => {
$w(“#text66”).text = ${totalCount};
})
.catch((err) => console.error(“count query failed:”, err));

// Still needed for items created for the FIRST time
// (e.g. initial load, or repeater growing to show more items)
$w(“#repeater2”).onItemReady(($item, itemData, index) => {
updateRepeaterItem($item, itemData, index);
});

$w(“#dropdown1”).onChange(() => applyFilters());
$w(“#dropdown2”).onChange(() => applyFilters());
});

function applyFilters() {
const type = $w(“#dropdown1”).value;
const year = $w(“#dropdown2”).value;

$w(“#dropdown1”).disable();
$w(“#dropdown2”).disable();

let filter = wixData.filter();

if (type && type !== “RESET_ALL”) {
filter = filter.eq(“type”, type);
}
if (year && year !== “RESET_ALL”) {
filter = filter.eq(“year”, Number(year));
}

const thisRequestId = ++filterRequestId;

$w(“#dataset1”)
.setFilter(filter)
.then(() => {
if (thisRequestId !== filterRequestId) return; // stale, discard

  // Forces every CURRENTLY RENDERED item (reused or new)
  // to get its index/text corrected — fixes the reuse bug.
  refreshRepeaterItems();
  updateFilteredCount();
  console.log("Dataset filtered and order updated.");
})
.catch((err) => console.error("setFilter failed:", err))
.finally(() => {
  $w("#dropdown1").enable();
  $w("#dropdown2").enable();
});
}

// Single place that defines what a “row” looks like.
// Used by BOTH onItemReady (new containers) and forEachItem (reused containers).
function updateRepeaterItem($item, itemData, index) {
const rowNumber = index + 1;
$item(“#text45”).text = ${rowNumber};
$item(“#text67”).text = ${rowNumber};

if (!itemData.venue) {
$item(“#text61”).collapse();
} else {
$item(“#text61”).expand();
}
}

function refreshRepeaterItems() {
$w(“#repeater2”).forEachItem(($item, itemData, index) => {
updateRepeaterItem($item, itemData, index);
});
}

function updateFilteredCount() {
const filteredCount = $w(“#dataset1”).getTotalCount();
$w(“#text65”).text = ${filteredCount};
}