get index of class element with inline onclick - pure js no jQuery - javascript

so i have some class-elements:
<span class="show" onclick="show()">show</span>
<span class="show" onclick="show()">show</span>
<span class="show" onclick="show()">show</span>
when i click one of these elements i need the index for some reason. i know how to use jQuery, but thats not what i am asking for, here.
my js function should look something like this:
function show() {
var index = document.getElementsByClassName('show')[??];
alert(index);
}
How is that possible with pure javascript? NOTE: i have to stick with the onclick="show()" that cannot be changed.
i hope someone can help, thanks in advance :)

Just get the array of all the elements and find the current element who received the click
function show(el) {
var els = Array.prototype.slice.call( document.getElementsByClassName('show'), 0 );
console.log(els.indexOf(event.currentTarget));
}
<span class="show" onclick="show(this)">span 1</span>
<span class="show" onclick="show(this)">span 2</span>
<span class="show" onclick="show(this)">span 3</span>

You can try something like this:
Use addEventListener to bind event handlers. This will allow you to use this.
If you still need index of element, you can either loop over elements or convert NodeList into array and then use Array.indexOf
Sample
Onclick
function show(self){
var spans = document.querySelectorAll('.show');
console.log(Array.from(spans).indexOf(self))
}
<span class="show" onclick="show(this)">show</span>
<span class="show" onclick="show(this)">show</span>
<span class="show" onclick="show(this)">show</span>
addEventListener
function show(){
var spans = document.querySelectorAll('.show');
console.log(Array.from(spans).indexOf(this))
}
function registerEvent(){
var spans = document.querySelectorAll('.show');
for(var i = 0; i< spans.length; i++){
spans[i].addEventListener("click", show)
}
}
registerEvent();
<span class="show" >show</span>
<span class="show" >show</span>
<span class="show" >show</span>

If you absolutely insist on using the onclick attribute (even though you don't really need to):
// get live collection so you only need to call this once
var liveCollection = document.getElementsByClassName('show');
function show(event) {
// convert liveCollection to array for `.indexOf()`
// either ES6
var shows = [...liveCollection];
// or ES5
var shows = Array.prototype.slice.call(liveCollection);
var index = shows.indexOf(event.currentTarget);
alert(index);
}
.show {
cursor: pointer;
}
<span class="show" onclick="show(event)">show</span>
<span class="show" onclick="show(event)">show</span>
<span class="show" onclick="show(event)">show</span>
However, I would rather recommend you use delegated events to handle dynamically added elements, as using the onclick attribute is considered bad practice, but don't just take my word for it.
// see below for how to select the best container
var container = document.body;
// single event listener for all dynamically added elements
container.addEventListener('click', function (event) {
if (event.target.classList.contains('show')) {
show.call(event.target, event);
}
});
// get live collection so you only need to call this once
var liveCollection = container.getElementsByClassName('show');
function show(event) {
// convert liveCollection to array for `.indexOf()`
// either ES6
var shows = [...liveCollection];
// or ES5
var shows = Array.prototype.slice.call(liveCollection);
// this === event.target
var index = shows.indexOf(this);
alert(index);
}
.show {
cursor: pointer;
}
<span class="show">show</span>
<span class="show">show</span>
<span class="show">show</span>
The nice thing about delegated event handling is you don't need an onclick attribute to handle dynamically added elements, so this will work best for your particular usage.
It is recommended, but not necessary, that the event listener for the delegated events is attached to the most immediate container of all the dynamically added elements, so that the click event doesn't have to bubble up all the way to the document.body. This makes the handling more efficient.

If you're JUST looking for the index, you can pass that to the show() method.
<span class="show" onclick="show(0)">show</span>
<span class="show" onclick="show(1)">show</span>
<span class="show" onclick="show(2)">show</span>

Related

Set onclick event to a class of elements: how to get id of the one clicked? javascript only

The problem:
I have 134 elements which must have an onclick event attached.
I am doing this by now, on eeeeeeevery single one of them (and they have an ondbclick event attached too!):
<div id="id1" class="name" onclick="functionName(this.id)"></div>
<div id="id2" class="name" onclick="functionName(this.id)"></div>
<div id="id3" class="name" onclick="functionName(this.id)"></div>
but read in Eloquent Javascript (chapter 14) that this is considered bad practice, since it mixes html and javascript.
So I thought I could find a way to attach the onclick event to all of them together. I searched a few hours and tried a few things, like this: (from 'How do you set a JavaScript onclick event to a class with css' here on stackoverflow)
window.onload = function() {
var elements = document.getElementsByClassName('nameOfTheClass');
for(var i = 0; i < elements.length; i++) {
var OneElement = elements[i];
OneElement.onclick = function() {
//do something
}
}
}
Which got the click to work on the elements, but not my function.
My original function was receiving two values, the id and the innerHTML of the element that got clicked, and now I cannot find a way to access that information.
I tried OneElement.id and OneElement.innerHTML just to find out that it gets the id and innerHTML of the last of the elements in the document.
Any clues? Any help very much appreciated! :)
When an event is triggered in JavaScript, JavaScript passes an event object to the callback function. Pass that into the signature and you will gain access to element properties.
window.onload = function() {
const elements = document.getElementsByClassName('nameOfTheClass');
for (const element of elements) {
element.addEventListener("click", e => {
console.log("element was clicked", e.target.id, e.target.innerHTML);
})
}
}
<div id="id1" class="name">first</div>
<div id="id2" class="name">second</div>
<div id="id3" class="name">third</div>
<script type="text/javascript">
var nodes = document.querySelectorAll('.name');
Array.from(nodes).forEach(function (node) {
node.addEventListener('click', function (event) {
alert('you clicked' + event.target.textContent + ' with id: ' + event.target.getAttribute('id'));
// you might also use event.target.innerHTML here
});
});
</script>
There are two DOM apis I would recommend you use:
document.querySelector and document.querySelectorAll and
element.addEventListener('click', event => {/* ... */});
Those are my gotos for "vanilla js" dom manipulation.
See the example below for what you wanted.
Array.from(document.querySelectorAll('.name')).forEach(element => {
// for each element that matches the querySelector `.name`
element.addEventListener('click', clickEvent => {
// call your function when the element is clicked
// see the properties of a Dom Element here:
// https://developer.mozilla.org/en-US/docs/Web/API/Element
yourFunction(element.id, element.innerHTML);
});
})
function yourFunction(id, innerHtml) {
// use the values!
console.log({id, innerHtml});
}
<div id="id1" class="name">[click me] inner html 1</div>
<div id="id2" class="name">[click me] inner html 2</div>
<div id="id3" class="name">[click me] inner html 3</div>

call function with parameter unobstrusively

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>ClickMe</li>
<li>ClickMe</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
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).
Since it got reopened, I will answer.
There is no getElementByClassName there is a getElementsByClassName. You can not just bind to the collection directly. You would need to loop over the live html collection to add the events.
var anchors = document.getElementsByClassName("myClass");
for (var i = 0; i < anchors.length; i++) {
anchors[i].addEventListener("click", function(e) {
console.log(this.getAttribute("data-id"));
});
}
<ul id="myList">
<li>ClickMe</li>
<li>ClickMe</li>
</ul>
The easy answer is event delegation, one click event on the parent element, look at the event object for what was clicked and you have the element. Read the data attribute or id and you have the number.
var list = document.getElementById("myList");
list.addEventListener("click", function(e) {
console.log(e.target.getAttribute("data-id"));
});
<ul id="myList">
<li>ClickMe</li>
<li>ClickMe</li>
</ul>
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>clickMe</li>
<li>clickMe</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>

How to change class name of two IDs at same time using js?

I have two IDs in same name ! if any one clicked among them , i need to change the class name of the both IDs. i know we should use ID for single use. Because of my situation(I have two classes for button ) so i have moved to ID.
Her is my code if i click one id that name only changes another one is remains same
<button class="success" id="1" onClick="reply(this.id)"> Added </button>
<button class="success" id="1" onClick="reply(this.id)"> Added </button>
js function
function reply(clicked_id)
{
document.getElementById(clicked_id).setAttribute('class', 'failed');
var el = document.getElementById(clicked_id);
if (el.firstChild.data == "Added")
{
el.firstChild.data = "Add";
}
}
if i use instead of 'class' to id while renaming class which one will be renamed success class or 'class name 1' ?
You can't. Getelementbyid will only return one element. Probably the first one.
Pure JS Is Second Example
My JS Fiddle Example: http://jsfiddle.net/eunzs7rz/
This example will use the class attribute only to perform the switching that you need, its a extremely basic example as do not want to go beyond what is needed... Also i forgot to remove the id's in the JS Fiddle Example.. so just ignore them
THE CSS:
.success {
background-color:#00f;
}
.failed {
background-color:#f00;
}
THE HTML:
<button class="success"> Added </button>
<button class="success"> Added </button>
THE JAVSCRIPT:
$(function() {
$(".success").click(function(){
Reply(this);
});
});
function Reply(oElm) {
$(oElm).attr('class', 'failed');
}
EDIT - PURE JAVASCRIPT VERSION
Sorry, did not think to check the post tags if this was pure JS. But here you go anyway ;)
<style>
.success {
background-color:#00f;
}
.failed {
background-color:#f00;
}
</style>
<button class="success" onclick="Reply(this)"> Added </button>
<button class="success" onclick="Reply(this)"> Added </button>
<script>
function Reply(oElm) {
oElm.className = 'failed';
}
</script>
THE MAIN THING HERE
Once you have the element either by using 'this' or by using 'getElementBy', you can then simply use ".className" to adjust the class attribute of the selected element.
As already explained by others, id is for single use and is quicker than using class or type. So even if you have a group, if only one is ever used.. use an id.
Then you use the object/reference of 'this' from an event on an element, in this case the onclick... that will send that variable to the function / code called.
So using 'this' is a preferred option as it will always reference the element that it is used/called from.
pass elemenet, not it's Id
<button class="success" id="1" onClick="reply(this)"> Added </button>
<button class="success" id="1" onClick="reply(this)"> Added </button>
function reply(elem)
{
$(elem).setAttribute('class', 'failed');
if (elem.firstChild.data == "Added")
{
elem.firstChild.data = "Add";
}
}
the ID attribute must be unique or else it will get the last defined element with that ID.
See this for reference.
Use a class instead of an id. ids are supposed to be unique in a dom tree.
html:
<button class="success" onClick="reply()"> Added </button>
<button class="success" onClick="reply()"> Added </button>
js:
var ary_success = document.querySelectorAll(".success"); // once and forever. If the set of elements changes, move into function `reply`
function reply () {
var elem;
var s_myclasses;
for (var i=0; i < ary_success.length; i++) {
elem = ary_success[i];
s_myclasses = elem.getAttribute('class');
s_myclasses = s_myclasses.replace ( /(success|failed)/g, '' );
s_myclasses = s_myclasses + ' failed';
elem.setAttribute('class', s_myclasses );
if ( elem.firstChild.data.indexOf("Added") !== -1) {
elem.firstChild.data = "Add";
}
}
}
Live Demo here.
Notes
Make sure that you set ary_successin the onload handler or in an appropriately placed script section - at the timeof execution the buttons must be present in the dom ! If in doubt, move it to the start of reply' body.
If you employ jquery, the code simplifies (well...) to:
$(document).ready( function () {
$(".success").on ( 'click', function ( eve ) {
$(".success").removeClass("success").addClass("failed");
$(".success *:first-child:contains('Added')").text(" Add ");
});
});
Updates
Notes, Live Demo
Iterator method changed, every not supported on test platform

multiple span calls of javascript value

In my header I have
function addusr() {
document.getElementById("usrout").innerHTML = document.getElementById("usrin").value;}
and in my text I have
code-bla bla bla<span id="usrout"></span> bla!! It works!
but if I try to call <span id="usrout"></span> again on the same page at a different location, none of the others appear.
Example:
text <span id="usrout"></span> more text, code... another <span id="usrout"></span>...
...
..
...
another <span id="usrout"></span> ...
Only the first one appears, why is this? How can I fix it?
An ID needs to be unique. You might want to consider classes instead.
When you’ve assigned classes to the HTML elements, your JavaScript code may look like this:
function addusr () {
var usrin = document.getElementById("usrin").value,
usrout = document.getElementsByClassName("usrout");
Array.prototype.forEach.call(usrout, function (el) {
el.innerHTML = usrin;
});
}
Explanation:
Instead of getElementById, we’re using getElementsByClassName which returns an array of elements having that particular classname. Thus a loop is required to set the innerHTML property of each retrieved element.
First of all, using same ID in more than one element is WRONG and against RFC.
You should make it a CLASS, not ID, and then...
document.querySelector(".usrout").innerHTML = ...
Every single element needs a unique ID.
For example
<span id="usrout1"></span>
<span id="usrout2"></span>
Alternatively, you could use classes as mentioned already
<span class="green"></span>
<span class="green"></span>
Then use a CSS selector such as document.getElementByClass
Element IDs must be unique, so getElementById will only ever return (at most) one element.
You need to use a different search, perhaps querySelectorAll, to get all the applicable elements. You can then loop through them, and set the necessary comment.
For example:
function addusr() {
var inputValue = document.getElementById("usrin").value;
var outputs = document.querySelectorAll("span.usrout");
for (var i = 0; i < outputs.length; ++i) {
outputs[i].textContent = inputValue;
}
}
<input id="usrin" type="text" />
<button type="button" onclick="addusr();">Update</button>
<span class="usrout"></span>
<span class="usrout"></span>
<span class="usrout"></span>
<span class="usrout"></span>
<span class="usrout"></span>
<span class="usrout"></span>

jQuery Mouseover DOM

I have a number of elements (the total number of which I do not know). I want something to appear when I mouse-over any one of these elements (which is taken care of by having a mouseover bound to the shared class of these elements).
However, the thing that I want to appear on mouseover is dependent on what the cursor is over - so I need to get the DOM element under the cursor, without the luxury of being able to bind mouseover events to each element in code.
Any suggestions?
HTML:
<a id="say1" class="say" href="#" data-word="one">Say 'one'</a>
<a id="say2" class="say" href="#" data-word="two">Say 'two'</a>
<a id="say3" class="say" href="#" data-word="three">Say 'three'</a>
Javascript (with jQuery):
$(document).ready(function () {
$('.say').mouseover(function () {
alert($(this).data('word'));
});
});
Pure Javascript (without jQuery, it is not equivalent):
window.onload = function () {
var onmouseover = function (e) {
alert(e.target.getAttribute('data-word'));
};
var elems = document.getElementsByClassName('say');
for (var i = 0; i < elems.length; i += 1) {
elems[i].onmouseover = onmouseover;
}
};
Instead of calling alert function you may implement any logic.
Event delegation is your friend here.
See this post from Christian Heilmann on that topic http://www.icant.co.uk/sandbox/eventdelegation/.
HTH.
jQuery makes this easy with .each():
$('#container').bind('mouseover', function () {
$(".selector").each(function(){
// Do something $(this) = item clicked
$(this).toggleClass('.example'); // Toggle class is just an example
});
});
You can then check certain characteristics of $(this) and then do different things based on the values/characteristics.

Categories

Resources