REPEATERS & CORVID

Understanding the $item selector, itemData array, and how to use a repeater item's index.

 

The $item selector:

Usually when we try to identify an object we want to manipulate in Corvid, we use some tag such as $w('#myItem'). However, repeaters have another option.

If we use $w to mess with some element in a repeater, it applies to every single clone. If we want to mess with these clones on an individual basis, we use $item.

So, let's say we have a button inside our repeater that changes the value of a text element outside the repeater. We could write:

export function repeater1_itemReady($item, itemData, index) {

$w('#button1').click(() => {
       $w('#outsideText').text = itemData.text;

}

}

Because we used $w on button1, our outsideText will display the text field from the first row of our database no matter which repeater button is clicked. In order to set outsideText based on this clone's data, we write this instead:

export function repeater1_itemReady($item, itemData, index) {

$item('#button1').click(() => {
       $w('#outsideText').text = itemData.text;

}

}

Since outsideText is not inside our repeater, there are no clones of it, and so for it we use the standard $w selector.

The itemData array:

When we selected a single button1 clone, we used the $item selector and tied it to itemData.text. So what is itemData and what does the .text part do?

When we connect a repeater to a collection, Wix allows you to make all sorts of modifications like filters and hooks to the data. itemData represents the final form after all of these modifications have been made.

If you connected your repeater to a Wix database, each column in your database has its own field key. Clicking on a column's hamburger menu and clicking on the Manage Field option will show you the field key. In our button1 example, text is the field key of the column holding our outsideText value.

Thus, if we wanted to set outsideText to the value of a different column with field key text2, we would change our code to this:

 

export function repeater1_itemReady($item, itemData, index) {

$item('#button1').click(() => {
       $w('#outsideText').text =
itemData.text2;

}

}

But what if I want to connect it to a different column where the field key is text-column-two?  The dashes here will result in errors if you tried to run itemData.text-column-two, so instead we write this:

export function repeater1_itemReady($item, itemData, index) {

$item('#button1').click(() => {
       $w('#outsideText').text =
itemData['text-column-two'];

}

}

This has the same effect while being able to handle the dashes, and you can only ever use this notation if you choose to.

What if some rows in our text-column-two column are empty? We can write our code so that an error text shows when that row is empty. The exclamation mark in Javascript means not, so we can tweak our code like this:

export function repeater1_itemReady($item, itemData, index) {

$item('#button1').click(() => {

if (!itemData['text-column-two']) {

       $w('#outsideText').text = 'Sorry, no data found';

} else {

       $w('#outsideText').text = itemData['text-column-two'];

}

}

}

Using the index:

An index is automatically assigned to every item in the itemData array, beginning with zero. If we want to make it so that outsideText shows the index of the clone we clicked on instead before the value of text-column-two, we can use:

export function repeater1_itemReady($item, itemData, index) {

$item('#button1').click(() => {

if (!itemData['text-column-two']) {

       $w('#outsideText').text = index + ' Sorry, no data found';

} else {

       $w('#outsideText').text = index + ' ' + itemData['text-column-two'];

}

}

}

Lastly, let's say our repeater is pretty long and we want to give our visitor some idea of how many items they've scrolled through. Or maybe we've arranged our repeater in rows of 5 and we want to display the index of the first item in each row. The % symbol in Javascript means remainder. So we can add a condition to our function like this: 

export function repeater1_itemReady($item, itemData, index) {

if (index % 5 === 0) {

$item('#indexDisplay').text = index;

} else {

$item('#indexDisplay').text = '';

}

$item('#button1').click(() => {

if (!itemData['text-column-two']) {

       $w('#outsideText').text = index + ' Sorry, no data found';

} else {

       $w('#outsideText').text = index + ' ' + itemData['text-column-two'];

}

}

}

In this last example, we have some text element in the upper left-hand corner called indexDisplay. If the remainder of the index divided by 5 is 0, the indexDisplay shows us that clone's index, otherwise it shows nothing. This means only multiples of 5 will have their index displayed. However, because our indexes start at 0, this will result in what most people would consider to be item number six being labeled 5. So we simply add +1 to the display number: 

export function repeater1_itemReady($item, itemData, index) {

if (index % 5 === 0) {

$item('#indexDisplay').text = index + 1;

} else {

$item('#indexDisplay').text = '';

}

$item('#button1').click(() => {

if (!itemData['text-column-two']) {

       $w('#outsideText').text = (index + 1) + ' Sorry, no data found';

} else {

       $w('#outsideText').text = (index + 1) + ' ' + itemData['text-column-two'];

}

}

}

One thing to note if you hadn't noticed is that in this line:

(index + 1) + ' Sorry, no data found';

The first + sign is doing something different than the second. Because index and 1 are both numbers, the + calculates their sum. But the data in single quotes is a string, and so it concatenates the string to the number instead of getting the sum. So if for whatever reason you need to single out all items where the index starts with the number 3 (for example 31, 32, 33...), you couldn't easily do this like you would with a string or an array:

index[0]

Instead you would use this function to test what the first integer of the index is:

function get_first(num) {

const first = String(num).charAt(0);

return Number(first);

}

Combine that with a .forEach() of indexes, and you have your filtered array of items!