0

I have unordered lists below for fruits, animals, trees....about 100 buttons with same class:

<ul>
   <li><button class="bb" value="apple" onClick="aJax(value)">Apple</button></li>
   <li>Banana
      <ul>
         <li><button class="bb" value="green_banana" onClick="aJax(value)">Green_banana</button></li>
         <li><button class="bb" value="yellow_banana" onClick="aJax(value)">Yellow Banana</button></li>
      </ul>
   </li>
   <li><button class="bb" value="cherry" onClick="aJax(value)">Cherry</button></li>
   <li><button class="bb" value="cow..................and more....
</ul>

If clicked, I want to pass value to Ajax to return data from mySql:

  <script>
  function aJax(value)
      xmlhttp = new XMLHttpRequest();
      xmlhttp.open("GET","some_page.php?q="+value,true);
      xmlhttp.send();
      xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
       document.getElementById("some_id").innerHTML = xmlhttp.responseText;}
                                                }
                 }
  </script>

Is it possible to use addEventListener in my case above to replace each onClick? How to do it if I want to put the JS code on the header? Pls help, I need it in native JS. Thanks.

P. Lau
  • 165
  • 1
  • 11

4 Answers4

3

Yes, you can do it :

var bbs = document.getElementsByClassName("bb");
for(var i =0; i< bbs.length; i++){
  bbs[i].addEventListener('click', function(){
    var attr = this.value;
    console.log(attr);
  });
}
<ul>
   <li><button class="bb" value="apple" >Apple</button></li>
   <li><button class="bb" value="banana">Banana</button></li>
   <li><button class="bb" value="cherry">Cherry</button></li>
</ul>

Instead of console.log(attr); you can call your custom function

  • 2
    It is better to avoid anonymous functions when adding event listeners because if you want to remove them afterwards the 'removeEventListener' will fail since it needs exactly the same parameters. – Sotiris Kiritsis Jul 05 '17 at 14:13
  • Hi, I just change a bit of the ul li to make ul within ul, is your code still can be use? – P. Lau Jul 05 '17 at 14:40
1

try that :

window.addEventListener( 'load' , function () {

    var list = document.querySelectorAll( 'ul > li > button' );

    for ( var i = 0 , l = list.length ; i < l ; i++ ) {

        list[ i ].addEventListener( 'click' , function () {
            aJax( this.value );
        } );

    }

} );
1

the simplest way (no loops needed)

var container = document.querySelector("ul");
container.addEventListener("click", doSomething, false);
 
function doSomething(e) {
    if (e.target !== e.currentTarget) {
        var clickedItem = e.target.value;
        console.log(clickedItem);
    }
    e.stopPropagation();
}
<ul>
   <li><button class="bb" value="apple" >Apple</button></li>
   <li><button class="bb" value="banana">Banana</button></li>
   <li><button class="bb" value="cherry">Cherry</button></li>
</ul>

check this awesome article, I'm pretty sure it's what you're looking for Handling Events for Many Elements

taha
  • 997
  • 9
  • 17
  • will it run faster without loop? – P. Lau Jul 06 '17 at 02:52
  • Absolutely! there are 2 major benefits of using event delegation model. first, it's performance is much better in applications in which many events are generated. and second, it enables the handling of events by objects other than the ones which generate the events. It is a clean separation between design and usage of a component. – taha Jul 06 '17 at 06:25
1

While other answers are right, if your list is long, you might delegate the click to the ul element :

function logValue(evt){
  let target = evt.target;
  // only console.log if the click target has class "bb"
  if(target.classList.contains("bb")){
    console.log(target.value)
  }
}

// wait for the document to be loaded
window.addEventListener("load",()=>{
  let list = document.querySelector(".my-list");
  if(list){
    //delegate click handler to the <ul> element
    list.addEventListener("click", logValue);
  }
});
<ul class="my-list">
  <li><button class="bb" value="apple">Apple</button></li>
  <li>Banana
    <ul>
       <li><button class="bb" value="green_banana">Green_banana</button></li>
       <li><button class="bb" value="yellow_banana">Yellow Banana</button></li>
    </ul>
  </li>
  <li><button class="bb" value="cherry">Cherry</button></li>
</ul>
n00dl3
  • 21,213
  • 7
  • 66
  • 76
  • delegating the click to the `ul` is the best way to do it – taha Jul 05 '17 at 14:20
  • Hi, I just change a bit of the ul li to make ul within ul, is your code still can be use? – P. Lau Jul 05 '17 at 14:41
  • I edited, so you can check by yourself ;-) (yes it does work) – n00dl3 Jul 05 '17 at 14:43
  • The only rule is the element that will react to click must be a child of the `ul.my-list` element and only these "click-enabled" elements (that are children of `ul.my-list`) have the `bb` class. – n00dl3 Jul 05 '17 at 21:28