Velo Repeaters: Understanding the Scope of Selector Functions

Visit the Velo by Wix website to onboard and continue learning.

A selector function is used to select specific page elements so you can work with them in code. A scope defines which elements you can select and how they behave when they are selected. Depending on which selector you use, you will be able to select elements from the different scopes described below and the selected elements will behave accordingly.

There are two types of selector functions:

  • Global Scope Selectors
  • Repeated Item Scope Selectors

Global Scope

The $w() function that is available to your Page Code and masterPage.js files selects elements in the global scope.

A selector with global scope can be used to select any element that is not contained in a repeater. You can also use it to select an element that is contained in a repeater, but it is important to understand what that selection means.


When you select an element contained in a repeater from the global scope, and you get the value of one of the element's properties, you receive the value of that element's property from the repeater's item template.

For example, here templateText will be the text value of the myRepeatedText element from the repeater's item template.

Copy
1
$w.onReady( function () {
2
let templateText = $w("#myRepeatedText").text;
3
} );

When you select an element contained in a repeater from the global scope and you set the value of one of the element's properties or call one of the element's functions, the value is set or the function is called on the repeater's item template and all repeated instances of that element.

For example, here the item template will change so that "New Text" will be the text value of the myRepeatedText element. Also, all existing repeated items will have the text value of their myRepeatedText element set to "New Text".

Copy
1
$w.onReady( function () {
2
$w("#myRepeatedText").text = "New Text";
3
} );

And here the item template will change so that the myRepeatedImage element is hidden. Also, all existing repeated items will have their myRepeatedImage element hidden.

Copy
1
$w.onReady( function () {
2
$w("#myRepeatedImage").hide();
3
} );

Repeated Item Scope

There are two instances where you get a repeated item scope selector:

  • The $item parameter of the forEachItem(), forItems(), and onItemReady() event handlers.
  • When calling the $w.at() function and passing it an event whose context is "COMPONENT_SCOPE". This is usually done in an event handler that handles events on an element inside a repeater.

A selector with repeated item scope selects the instance of a repeating element in the current repeating item and its descendants. You cannot change the item template using a selector with repeated item scope.

For example, here when the myRepeatedImage element is clicked, the text value of the myRepeatedText element from the repeated item where the image was clicked will be changed to "Selected". All the other myRepeatedText elements in the other items of the repeater will not be affected.

Copy
1
$w.onReady( function () {
2
$w("#myRepeatedImage").onClick( (event) => {
3
let $item = $w.at(event.context);
4
$item("#myRepeatedText").text = "Selected";
5
} );
6
} );

Example

To demonstrate the different selector scopes and what selecting from those scopes means, we will use the following example.

Here we have a repeater that contains a number of items set in the editor. Each item can be either "selected" or "unselected". The selected status of each item is indicated by that item's itemSelected text element. The number of selected items in the repeater is indicated by the page's numSelected text element. 

There are several ways a user can select elements:

  • Click the selectAll button to select all the items.
  • Click the selectLeft or the selectRight buttons to select all the items in the left or right column.
  • Click a repeatedImage instance to select the item with that image.

Here is the code:

Copy
1
$w.onReady( () => {
2
$w("#selectAll").onClick( (event) => {
3
$w("#itemSelected").text = "Selected";
4
$w("#numSelected").text = $w("#myRepeater").data.length.toString();
5
} );
6
7
$w("#repeatedImage").onClick( (event) => {
8
let $item = $w.at(event.context);
9
if($item("#itemSelected").text === "Unselected") {
10
$item("#itemSelected").text = "Selected";
11
$w("#numSelected").text = (Number($w("#numSelected").text) + 1).toString();
12
}
13
else {
14
$item("#itemSelected").text = "Unselected";
15
$item("#numSelected").text = (Number($w("#numSelected").text) - 1).toString();
16
}
17
} );
18
19
$w("#selectLeft").onClick( (event) => {
20
selectColumn(0, 2);
21
} );
22
23
$w("#selectRight").onClick( (event) => {
24
selectColumn(1, 2);
25
} );
26
} );
27
28
function selectColumn(columnIndex, numColumns) {
29
$w("#myRepeater").forEachItem( ($item, itemData, index) => {
30
if(index % numColumns === columnIndex && $item("#itemSelected").text === "Unselected") {
31
$item("#itemSelected").text = "Selected";
32
$item("#numSelected").text = (Number($w("#numSelected").text) + 1).toString();
33
}
34
} );
35
}

Let's analyze this code one section at a time.


First, let's look at the onClick() event handler for the selectAll button.

Copy
1
$w("#selectAll").onClick( (event) => {
2
$w("#itemSelected").text = "Selected";
3
$w("#numSelected").text = $w("#myRepeater").data.length.toString();
4
} );

All selectors in this snippet are global selectors. That means that the selection of the itemSelected text element on line 2 is from the global scope. So when its text value is set, the text value of the itemSelected element in the repeater's item template and the text values of all the repeated itemSelected elements in all of the repeated items are set to "Selected". This is what allows us to "select" all the items in one line of code. (We have also changed the item template. But since we will not be creating any new items, the change is of no consequence.)


Next, let's look at the onClick() event handler for the repeatedImage element.

Copy
1
$w("#repeatedImage").onClick( (event) => {
2
let $item = $w.at(event.context);
3
if($item("#itemSelected").text === "Unselected") {
4
$item("#itemSelected").text = "Selected";
5
$w("#numSelected").text = (Number($w("#numSelected").text) + 1).toString();
6
}
7
else {
8
$item("#itemSelected").text = "Unselected";
9
$item("#numSelected").text = (Number($w("#numSelected").text) - 1).toString();
10
}
11
} );

On line 2 we create a repeated item scope selector. That means all the selections using that selector in the body of the function are repeated item scope selections. So when we select a repeated element, such as the itemSelected text element, we are selecting the individual instance of that element that is in the same repeated item as the image that was clicked. All the other itemSelected elements in the other items of the repeater will not be affected.

Notice that on lines 5 and 9 we also use a global selector to select an element outside the repeater and change the value of one of its properties.


Finally, let's look at the onClick() event handler for the selectLeft and selectRight buttons.

Copy
1
$w("#selectLeft").onClick( (event) => {
2
selectColumn(0, 2);
3
} );
4
5
$w("#selectRight").onClick( (event) => {
6
selectColumn(1, 2);
7
} );

Both of these event handlers call the selectColumn() function which "selects" all of the items in a given column.

Copy
1
function selectColumn(columnIndex, numColumns) {
2
$w("#myRepeater").forEachItem( ($item, itemData, index) => {
3
if(index % numColumns === columnIndex && $item("#itemSelected").text === "Unselected") {
4
$item("#itemSelected").text = "Selected";
5
$item("#numSelected").text = (Number($w("#numSelected").text) + 1).toString();
6
}
7
} );
8
}

The $item parameter of the forEachItem() function is a repeated item scope selector. That means all the selections using that selector in the body of the function are repeated item scope selections. So when we select the itemSelected text element, which is a repeated element, we are selecting the individual instance of that element for the specific item of the current iteration of the forEach loop. All the other itemSelected elements in the other items of the repeater will not be affected.

Was this helpful?
Yes
No