Adding onClick event to multiple elements

I have a number of VectorImage icons on a page, for which I wish to add an onClick event. Each icon, when clicked, will display information from a simple database collection. I have achieved this by using a .forEach loop on all VectorImages, but am now looking to refine this code as my page may contain other VectorImages which are not part of the collection.
My current thinking is to create an array containing just the icon id’s and then loop through this in the same way as I did with the VectorImages. Rather than “hard-coding” the array, I am querying my collection and push ing each id into the array. Again, this works fine in principle, but as it is a query, there is a delay and my subsequent .forEach loop starts before the array is populated and the loop tries to run on an empty array. I have tried nesting the entire .forEach loop inside the .then() code, but I get an error: “icon.onClick is not a function” .
I’m hoping that someone is able to offer a neat solution to this but am also keen to understand why my attempts don’t work. I’m a relative newcomer to Velo, but learning quickly :grinning:
My code is below:

let iconList = [] // initialise empty iconList array
wixData . query ( “places” ) // create query for the “places” collection
. find () // run the query
. then (( results ) => {
results.items . forEach ( entry => { // loop through each entry in the collection
iconList . push ( “$w('#” + entry.icon + “')” ) // push the icon id to the iconList array
})

        // this is where I tried inserting the Assign onClick events loop below 

    }) 

// Assign onClick events 
// $w("VectorImage").forEach(icon => { // loop through all vector images on page (my original method) 
iconList . forEach ( icon  => {  // loop through all items in the iconList array (my new method) 
    icon . onClick (( event ) => {  // create "on click" event for icon 
        wixData . query ( "places" )  // create query for the dataset 
            . eq ( "icon" ,  icon.id )  // filter criteria icon = clicked icon 
            . find ()  // run the query 
            . then ( res  => { 
                $w ( '#text1' ). text  =  res.items [ 0 ]. title  // set text1 element = title 
                $w ( '#text2' ). text  =  res.items [ 0 ]. description  // set text2 element = description 
                **let**  flyEffects  = {  // set animation effect 
                    "direction" :  "top" , 
                    "duration" :  200 
                } 
                $w ( '#info' ). show ( "fly" ,  flyEffects )  // show info box, using animation effects 
            }) 
    }) 
})

You got the concept right, let’s refactor a little bit to make it work in a cleaner way.

Using async/await you can easily await for the data before doing anything else. It also allows you get rid of the scoped .then() method.

import wixData from 'wix-data'

const flyEffects = {
  // set animation effect
  direction: 'top',
  duration: 200,
}

const queryIcons = async () => {
  const { items } = await wixData.query('places').find() //Destructuring the query result to get the items array
  return items.length > 0 ? items.map((item) => `item.icon) : null //Map the items array to get the icon property of each item
}

const clickAction = async (e) => {
  //Click action that will be executed when the user clicks on the button
  const { id } = e.target
  const { items } = await wixData
    .query('places') // create query for the dataset
    .eq('icon', id) // filter criteria icon = clicked icon
    .find()
  if (items.length > 0) {
    $w('#text1').text = items[0].title // set text1 element = title
    $w('#text2').text = items[0].description // set text2 element = description

    $w('#info').show('fly', flyEffects)
  }
  // show info box, using animation effects
}

$w.onReady(async () => {
  const iconsList = await queryIcons()
  iconsList.forEach((icon) => {
    $w(`#${icon}`).onClick(clickAction) //The error was here, the WIX Element syntax was wrong
  }) // add click event to each icon
})


Thank you so much for taking the time to advise on this @bwprado . Whilst I don’t (yet) completely understand your suggested code, I certainly get the gist of it. I’ve tried running the revised code and am still getting the same TypeError: icon.onClick is not a function that I got with my code. When I hover over the onClick line in the editor, it tells me that property “onClick” does not exist on type “string” .
Any thoughts?

1 Like

I just saw the error I did, it is missing the correct WIX Element syntax. I’m going to correct my code. Just a minute.

That’s perfect… it’s all making sense now. Thank you again for your help with this… it’s much appreciated.