0

I want to set a click event for each list like this:

Example 0. use an inline event handlers

<ul class="fruits">
    <li class="apple" onclick="show(apple)">Apple</li>
    <li class="orange" onclick="show(orange)">Orange</li>
    <li class="cherry" onclick="show(cherry)">Cherry</li>
    <li class="grape" onclick="show(grape)">Grape</li>
    <li class="kiwi" onclick="show(kiwi)">Kiwi</li>
</ul>

As shown above, Inline event handlers, is simple and intuitive, but it's deprecated. so I will use addEventListener method. However, the latter is many different ways to write and I don't know the best.

Here are a few writing ideas I've come up with.

Example 1. Get the arguments value from class name or data-attribute.

const fruits = document.querySelectorAll(".fruits> li");

fruits.forEach((fruit) => {
  fruit.addEventListener("click", function () {
    // use the class name for matching with arguments. more option is data-attributes.
    const fruitName = fruit.className;
    show(fruitName);
  });
});

Example 2. Get the arguments value from a list in JS.

const fruitList = ["apple", "orange", "cherry", "grape", "kiwi"];

for (let fruit of fruitList) {
  let fruitElem = document.querySelector(`.fruits> li.${fruit}`);
  fruitElem.addEventListener("click", function(){
      show(fruit)
  });
}

Example 3. Get the arguments value from a list, more complex than EX2 for future management, in JS.

const fruitList = [
    {event: "click", key: "apple", func: show},
    {event: "click", key: "orange", func: show},
    {event: "click", key: "cherry", func: show},
    {event: "click", key: "grape", func: show},
    {event: "click", key: "kiwi", func: show},
]

for (let fruit of fruitList) {
    let fruitElem = document.querySelector(`.fruits> li.${fruit.key}`);
    fruitElem.addEventListener(fruit.event, function(){
        fruit.func(fruit.key);
    });
}

What I would like to ask is:

  • Which is the best way to do this (EX0-3)?
  • If it was you, how to implement this?

Please teach me.

Rin
  • 41
  • 5
  • 1
    That is totally opinion-based. There is no right or wrong answer here. If I have to choose one of the aforementioned options then definitely I'd go with `Example 1` – DecPK Aug 31 '21 at 04:28

1 Answers1

1

A combination of data attributes, which are designed to attach information to HTML elements that is not related to layout or presentation, and event delegation to avoid multiple event handlers to do the same thing is an alternative way of handling this design.

To illustrate with the posted example:

"use strict";
function show( fruit) {
   console.log("show(%s)", fruit);
}

const fruitList = document.getElementById("fruitList");
fruitList.addEventListener("click",
    event => {
        let li = event.target.closest('li');
        if( li && (li.parentNode === fruitList)) {
            show( li.dataset.fruit)
        }
    }
);
li {
   cursor: pointer;
   margin-bottom: 0.5em;
}
<ul id="fruitList">
    <li data-fruit = "apple">Apple</li>
    <li data-fruit ="orange">Orange</li>
    <li data-fruit ="cherry"><em>Cherry</em></li>
    <li data-fruit ="grape">Grape</li>
    <li data-fruit ="kiwi">Kiwi</li>
</ul>

Because one answer rarely fits all situations, if the class attributes are actually used to style layout using rules in a style sheet, then they might serve as a substitute for data attributes as a way of determining what fruit to show.


Updated to ignore clicks that are not on list items (or child elements thereof) within the list being monitored.

Clicks to ignore include

  • Clicks within list bullet areas,
  • Clicks In padding or borders around li elements if the default CSS box-sizing value is in effect,
  • Clicks in margins set on list elements
  • Clicks that are within a list-item but the list item belongs to an outer list within which the monitored list is nested.

The click handler also allows clicking on child elements of list items that do not set event.target - see the em tags around "Cherry" for testing.

traktor
  • 17,588
  • 4
  • 32
  • 53
  • 1
    Thanks to give a solution. Your solution is better than any example. However, If I click on a padding area in ul, I catch the following log: ```show(undefined)``` So, I think need to add a code to return if the clicked area isn't li element such as this: ```if (event.target.tagName != 'LI') return;``` How would you solve this problem? – Rin Aug 31 '21 at 15:12
  • Good catch! See the updated answer for a more general solution. Your suggestion could work but doesn't cover cases where s list items have child elements or list elements are nested in list items of an outer list. – traktor Sep 01 '21 at 01:00