I’m trying to solve an issue that I’m facing since several days now.
I have 2 major elements on a webpage :
- A repeater (repeater1) where each item is refering to a learning course.
- A dropdown box to filter the courses by category
In the repeated items, i have a « show more/less » button that hide or display some text description. But when i click on this button after having change the category (so after having refreshed the data of the repeater), the actions in the button_click event handler are executed several
times instead of being executed one time.
Here is my code:
const maxChar = 190;
$w.onReady(function () {
$w("#repeater1").collapse();
$w("#repeater1").onItemReady( ($item, itemData, index) => {
$item("#image1").src = itemData.image;
$item("#text17").text = itemData.title;
let fullTextDescription = itemData.description;
if ( fullTextDescription.length > maxChar){
let shortText = fullTextDescription.substr(0, maxChar) + "...";
$item("#text15").text = shortText;
} else {
$item("#button3").collapse();
}
$item("#button3").onClick( (event) => {
let fullText = itemData.description;
let shortText = fullText.substr(0, maxChar) + "...";
console.log("Button 3 label is : " + $item("#button3").label);
if ( ($item("#button3").label) === "Show more..." ){
console.log("Show more clicked, so short text changed to full text and button label changed to show less");
$item("#text15").text = fullText;
$item("#button3").label = "Show less...";
} else {
console.log("Show less clicked, so full text changed in short text and button label changed to show more");
$item("#text15").text = shortText;
$item("#button3").label = "Show more...";
}
console.log("Button 3 label is now : " + $item("#button3").label);
} );
wixData.query("eModules")
.ascending("index")
.find()
.then( (results) => {
if( results.items.length > 0) {
$w("#repeater1").data = results.items;
$w("#repeater1").expand();
} else {
$w("#repeater1").collapse();
}
} );
});
export function dropdown1_change(event) {
//Add your code for this event here:
let $selectedCategory = "";
wixData.query("Categories")
.eq("title", $w('#dropdown1').value)
.find()
.then( (results) => {
let $firstItem = results.items[0];
$selectedCategory = $firstItem._id;
wixData.query("eModules")
.ascending("index")
.eq("categorie", $selectedCategory)
.find()
.then( (results2) => {
$w("#repeater1").data = results2.items;
} )
.catch( (err) => {
let errorMsg = err;
} );
} );
}
Ans this is how it looks lile when clicking on show more after having changed the category (so repeater data refresh) several times :
Nothing happened when having clicked on “Show more” and the console log shows twice the action like if the process would be automatically executed twice ! Can’t figured out why
I tried to connect both elements (repeater and dropdown listbox) to a dataset and also without a dataset (via code). I have the same situation in both configurations.
Based on my code, can anyone help me on this please ?
After further investigations, it appears that each time the data of the repeater is refreshed (after a change of value in the dropdown listbox), it amplifies the problem !
That means, if I change once the category via the change event handler of dropdown1, the first data refresh has no impact on the number of actions made by button3 (has seen in my previous post). If i change a second time the category, the process performed by button3 is executed twice (as seen in the previous post). If i change a third time the category in dropdown1, the process performed by button3 is executed three times. If I change the selection four times, the process performed by button 3 is executed 4 times …
It’s like if each time I do a " $w ( “#repeater1” ). data = results2 . items ;" in the dropdown1_change function, another instance of “$item ( “#button3” ). onClick ( ( event ) => { …” is added to the " $w ( “#repeater1” ). onItemReady ( ( $item , itemData , index ) => {" function for each element. So that when I click on the button, several instances of the onclick action would be performed …
Please I REALLY need some help on that as I’m stuck since several days now
@jonatandor35 Thanks J.D for your reply and sorry if the post was too long. I wanted to be the most accurate as possible.
Let’s then try to make a short summary:
I have a “Show more/less” button contained in each item of a repeater that shows the full or part description of each item.
I also have a dropdown listbox to filter categories of item and which refresh the data of the repeater.
Problem: Each time I change the value of the dropdown list, the data of the repeater is well refreshed but when I click on the “Show more/less” button, the action performed by the button_click is executed as many times as I have selected a different value in the dropdown list (so as many times as the data of the repeater has been refreshed).
@rod_didier from the link that Jeff’s posted:
" Although it is convenient to do so using the scoped $item selector, this practice may cause several event handlers to be set for the same item"
So try the alternative ways.
Thank you Jeff. This article seems to deal with my issue. What I understand is that it is preferable not to use the onItemReady() function but the scoped $item selector. But I would need more info. Does that mean, that I should take the button3_click event out of the onItemReady() function and use a “forItem…” statement instead ?
To be honest, I haven’t looked at this in a while.
But we say here you shouldn’t use $item. " Although it is convenient to do so using the scoped $item selector, this practice may cause several event handlers to be set for the same item , as well as add multiple copies of the callback function to the event handler, affecting the performance of your site."
You want to use one, or a combination of the other APIs listed.
EDIT: Look at J.D’s blog post that he shared. It will guide you.
@jonatandor35@jeff, many thanks both of you ! Thanks to this article, I could definitively solve my issue using the event.context method ! Now it works perfectly.
my code is now as follow:
export function button3_click(event) {
let $item = $w.at(event.context);
// get the ID of the repeated item which fired an event
const itemId = event.context.itemId;
// get all repeater's data, it's stored as an array of objects
const data = $w("#repeater1").data;
// use the array methods to find the current itemData and index
const itemData = data.find((item) => item._id === itemId);
const index = data.findIndex((item) => item._id === itemId);
let fullText = itemData.description;
let shortText = fullText.substr(0, maxChar) + "...";
if ( ($item("#button3").label) === "Show more..." ){
$item("#text15").text = fullText;
$item("#button3").label = "Show less...";
} else {
$item("#text15").text = shortText;
$item("#button3").label = "Show more...";
}
}