1

I have a functional code, but would like to improve it for the sake of learning.

I did quite a lot of research and only found a solution using jQuery, but as i'm still a beginer I would like to make in in plain js first. [How do I get HTML button value to pass as a parameter to my javascript?

Basically, I have a list, and I want each entry of this list to call a function with a given parameter, being a natural number.

Among the classic / obstrusive techniques we have:

<li><a href="#" id="0" class="myClass" onclick="return myFunction(0);" >clickMe</a></li>
<li><a href="#" id="1" class="myClass" onclick="return myFunction(1);" >clickMe</a></li>
...

or

<li><a href="javascript:myFunction(0)" id="0" class="myClass">ClickMe</a></li>
<li><a href="javascript:myFunction(1)" id="1" class="myClass">ClickMe</a></li>
...

and

<li><button class="myClass" onClick="return myFunction(0);">ClickMe</button></li>
...

wich indeed call myFunction() with the parameter set to 0, 1 and so on.

But I've read that it wasn't recomended to do so as

  • I'm using the <a> tag while I'm not intending to link anywhere.
  • it mixes HTML and Javascript and that separation of concern is the way to go whenever possible

Then there is the unobstrusive way

<li><button id="0" class="myClass">clickMe</button></li>

completed by

document.getElementById("0").onclick = function (){myFunction()}

This works, but I can't find a way to set my parametter. If, for instance, I add a value="0" attribute to my button, or myVar="0", I can't use value as a variable as it isn't declared, and it doesn't set the new value of myVar, thus myFunction is called with the wrong parameter being myVar="myVarPreviousValue"

Using GetElementsByClassName : EDIT: updated

Previously we used document.getElementById, however this may be very inconvinient if the list is long as we would have to create an event listner for every button. In such context, the use of document.getElementsByClassName seems appropriate.

As pointed by epascarello there's a nice explaination for the use of this method here Document.getElementsByClassName not working.

However this thread can be completed by precising how to get a variable value that is set in the elements of a given class in order to call a function with a given parameter

Bottom line question

How to, unobstrusivelly, call a function with a given parameter when the user click on some html content that have a given class (could be a <li>, <button>, <span>, <div> as you think is best)

Thank's in advance J.

Edit : updated the question related to the use of getElementsByClassName

Community
  • 1
  • 1
jbonlinea
  • 192
  • 1
  • 9

3 Answers3

2

Then there is the unobstrusive way

<li><button id="0" class="myClass">clickMe</a></li>

completed by

 document.getElementById("0").onclick = function (){myFunction()}

(Side note: You have <button ...></a> there, probably meant </button> at the end.)

In that specific case, just

document.getElementById("0").onclick = function (){ myFunction(0); };
// ------------------------------------------------------------^

...but I'd always advocate addEventListener instead, so the code plays nicely with others:

document.getElementById("0").addEventListener("click", function (){ myFunction(0); }, false);

(If you have to support obsolete browsers like IE8, this answer has a cross-platform hookEvent you can use instead of addEventListener.)

If you want to use the same handler and put the argument on the element, you can use the id or a data-* attribute:

 <li><button id="0" data-value="0" class="myClass">clickMe</button></li>

completed by

document.getElementById("0").addEventListener("click", myFunction, false);

then

function myFunction() {
    var parameter = this.getAttribute("data-value");
    // or var parameter = this.id;
    // ...
}

Here's an example using querySelectorAll to handle all button elements with a data-value attribute, and showing the data-value attribute when clicked:

var buttons = document.querySelectorAll("button[data-value]");
Array.prototype.forEach.call(buttons, function(btn) {
  btn.addEventListener("click", handler, false);
});
function handler() {
  console.log("Value: " + this.getAttribute("data-value"));
}
<button type="button" data-value="one">I'm 'one'</button>
<button type="button" data-value="two">I'm 'two'</button>
<button type="button" data-value="three">I'm 'three'</button>
<button type="button" data-value="four">I'm 'four'</button>

Side note: While it's valid HTML, I would generally avoid starting an id value with a digit, because although they work with getElementById, they're awkward to use in CSS selectors (#0 is invalid, for instance).

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Hi, tanks for the proposals, works like a charm ! Now it seems that to be the least obtrusive as possible it would be recommended to use a different handler for each element, but maybe there are also cases when setting the parameter in the element and use the same handler is best? – jbonlinea Dec 15 '16 at 19:45
0

If you have a predefined function, you can do

var elements = document.querySelectorAll(".myClass");
for (var i=0;i< elements.length;i++) {
  elements[i].onclick = myFunction;
}

and use a data-attribute to pass the data or this.id if that is enough

function myFunction(e) {
  e.preventDefault(); // cancel click
  e.stopPropagation(); // cancel event bubbling 
  console.log(this.id, this.getAttribute("data-val")||this.value);
}
window.onload = function() {
  var elements = document.querySelectorAll(".myClass");
  for (var i = 0; i < elements.length; i++) {
    elements[i].onclick = myFunction;
  }
}
<ul>
  <li><a href="#" id="link0" data-val="value 0" class="myClass">clickMe</a></li>
  <li><a href="#" id="link1" data-val="value 1" class="myClass">clickMe</a></li>
</ul>
<ul>
  <li><button type="button" id="but0" value="value 0" class="myClass">clickMe</button></li>
  <li><button type="button" id="but1" value="value 1" class="myClass">clickMe</button></li>
</ul>
<ul>
  <li id="link0" data-val="value 0" class="myClass">clickMe</li>
  <li id="link1" data-val="value 1" class="myClass">clickMe</li>
</ul>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • Then perhaps :focus or onfocus – mplungjan Dec 12 '16 at 18:15
  • Hi thank for your great input, very thoughtful for me, in the end for cross browser compatibility the only viable solution I've found to feeding nested list is to place their content in a dedicated span class. In this context I would think that the use of a button might be recommended as it is dedicated to be clicked rather than turn a span or a list into a clickable friendly design through CSS? Still super complete and helpful answer. Thanks – jbonlinea Dec 15 '16 at 19:51