Get dynamically created element that was click javascript - javascript

I'm trying to track what buttons users click via javascript/jquery. I have the following code
$(document).on('click', '[data-tracker]', function( event ) {
var target = event.target;
var targetName = $(target).data('tracker');
console.log(targetName);
});
<button data-tracker="test1">test1</button>
<i data-tracker="test2">test2</i>
<img data-tracker="test3">
At the moment this works as I want it to. When someone clicks on an element on the page that has the data-tracker attribute I log the value in the console.
I'm using datatables on some pages which dynamically creates elements from json returned from the server. I can't figure out how to record elements that have been dynamically created.
So all in all I want 1 function that will check if a user clicks on an element with the data-tracker attribute and output it's value to the console.

First of all instead of something like this
$(document).on('click', '[data-tracker]', function( event ) {
var target = event.target;
var targetName = $(target).data('tracker');
console.log(targetName);
});
You can do this
$(document).on('click', '[data-tracker]', function() {
var targetName = $(this).data('tracker');
console.log(targetName);
});
Secondly, the reason of this behavior may be because .data() function works that way
Store arbitrary data associated with the specified element. Returns the value that was set.
So when you dynamically add an element with attribute data-tracker there is no value set because it was not stored. So instead of using .data() just use .attr().
$(document).on('click', '[data-tracker]', function() {
var targetName = $(this).attr('data-tracker');
console.log(targetName);
});
Here is a snippet
$(document).on('click', '[data-tracker]', function() {
console.log($(this).attr('data-tracker'));
});
var num = 0;
$("#addElement").on('click', function() {
$("<div>").attr('data-tracker', 'test value ' + num).html('Test value' + num).appendTo(".content");
num++;
});
[data-tracker] {
cursor: pointer;
color: #F00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="addElement">Add element</button>
<div class="content">
<div data-tracker="value1">Value 1</div>
<div data-tracker="value2">Value 2</div>
<div>Test</div>
<div data-tracker="value3">Value 3</div>
<div data-tracker="value4">Value 4</div>
</div>

Your code looks OK to me. You are probably making some mistake when added elements with JSON, make sure you get that correct.
Here I've added a button to add elements to the page dynamically, you can verify
$(document).on('click', '[data-tracker]', function( event ) {
var target = event.target;
var targetName = $(target).data('tracker');
console.log(targetName);
});
$("#new").click(function(){
$("#d").append(`<button data-tracker="test1">test1</button>
<i data-tracker="test2">test2</i>
<img data-tracker="test3">`)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="d">
<button data-tracker="test1">test1</button>
<i data-tracker="test2">test2</i>
<img data-tracker="test3">
</div>
<br/>
<button id="new">Add</button>

I am assuming the data-tracker is a class name. And here is a example of how you adding a onclick event to all element with the same class name
a = document.getElementsByClassName("data-tracker")
for (var key in a) {
if (a.hasOwnProperty(key) && Number.isInteger(parseInt(key))) {
a[key].addEventListener("click", function(){console.log('hi')});
}
}
<input type="button" class="data-tracker" value="button1"></input>
<input type="button" class="" value="button2"></input>
<input type="button" class="data-tracker" value="button3"></input>

Related

How to dynamically remove elements in javascript?

Is there a way to dynamically remove elements with javascript or jquery. Suppose I have a function createElements() which creates new element and another function removeElement() which is suppose to remove the corresponding element. You will notice that when you run the snippet that when you click on the remove button all the element is gone! How could I implement this code? Isn't there a jquery selector where i could simply use removeElement(this) or somenething like that? Any suggestions are most welcome :) thank you.
function createElements() {
const boom = document.getElementById('boom');
boom.insertAdjacentHTML(
'beforeend', '<div class="newElem"><p >new element created dynamically yay!</p><button onclick="removeElement()">remove</button></div>'
);
}
function removeElement() {
alert('element removed dynamically boOoOoOoOooo!')
$('.newElem').remove();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="boom">
</div>
<br>
<button onclick="createElements()">Create new element</button>
You can do it like this:
function createElements() {
const boom = document.getElementById('boom');
boom.insertAdjacentHTML(
'beforeend', '<div class="newElem"><p >new element created dynamically yay!</p><button onclick="removeElement(this)">remove</button></div>'
);
}
function removeElement(element) {
alert('element removed dynamically boOoOoOoOooo!')
$(element).parent(".newElem").remove();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="boom">
</div>
<br>
<button onclick="createElements()">Create new element</button>
You just need to follow one single API. Use either pure JavaScript or jQuery. I would also suggest you to use unobstructive approach. Also, the way you remove the elements is wrong. You are removing everything.
See this way:
$(function() {
$("button#add").click(function() {
$("#boom").after('<div class="newElem"><p >new element created dynamically yay!</p><button class="remove">remove</button></div>');
});
$(document).on("click", ".remove", function() {
alert('element removed dynamically boOoOoOoOooo!')
$(this).closest(".newElem").remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="boom">
</div>
<button id="add">Create new element</button>
To be able to always delete the div that encompasses the remove button, you have to traverse the DOM tree. There are lots of jQuery goodies for this: http://api.jquery.com/category/traversing/
In this particular case, I would do the following:
var elementCounter = 0;
function createElements() {
const boom = document.getElementById('boom');
boom.insertAdjacentHTML(
'beforeend', '<div class="newElem"><p >'+elementCounter+': new element created dynamically yay!</p><button onclick="removeElement(event)">remove</button></div>'
);
elementCounter++;
}
function removeElement(event) {
alert('element removed dynamically boOoOoOoOooo!')
$(event.target).closest('.newElem').remove();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="boom">
</div>
<br>
<button onclick="createElements()">Create new element</button>
So you pass on the click event to the function as a parameter, and then with event.target you find out which button was clicked. $(event.target).closest(".newElem") will get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.

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>

Changing multiple button color separately when clicked

I'm having troubles with my javascript code, I have a snippet that creates a number of button depending on the loop range, the buttons share the same class but the ids are different
<div class="panel-footer" id="loop">
<ul class="post-action">
{% for i in range %}
<button class="btn btn-success guess" id="{{ i }}" value="{{ i }}" onclick="transferField(this.value)">{{ i }} </button>
{% endfor %}
</ul>
</div>
I am trying to change the color of each button when it is clicked and when clicked again changes back to default color but its not working fine, when i click on button 5 it changes color but once i click on button 6, it wont change color until i click button 6 or click another button again. Here is the js code:
<script>
clicked = true;
$(".guess").click(function(){
xyz = this.id
console.log(xyz)
if(clicked){
$('#' + this.id).css('background-color', '#FF8E2B');
clicked = false;
} else {
$('#' + this.id).css('background-color', '#27AE60');
clicked = true;
}
});
</script>
What have i done wrong?
Your problem is you are using clicked as a global variable.
Just store clicked in this.
$(".guess").click(function(){
xyz = this.id
console.log(xyz)
if(this.clicked){
$(this).css('background-color', '#FF8E2B');
this.clicked = false;
} else {
$(this).css('background-color', '#27AE60');
this.clicked = true;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="panel-footer" id="loop">
<ul class="post-action">
<button class="btn btn-success guess" id="one" value="one" > one</button>
<button class="btn btn-success guess" id="two" value="two" > two</button>
<button class="btn btn-success guess" id="three" value="three" > three</button>
</ul>
</div>
You are trying to "track" the state of multiple buttons using a single var, of course this wont work
try the following instead
$(".guess").click(function(){
var $this = $(this);
var clicked = $this.data('clicked');
if(clicked) {
$this.css('background-color', '#FF8E2B');
} else {
$this.css('background-color', '#27AE60');
}
$this.data('clicked', !clicked);
});
You can store an array of color for each element at data-* of element, use .data(), Array.prototype.reverse() to toggle to array, set background to element at index 0 of array
$("button").on("click", function() {
$(this).css("background", $(this).data().colors.reverse()[0])
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button data-colors='["#FF8E2B", "#27AE60"]' style="background:#FF8E2B">click</button>
What have i done wrong?
The main issue you have with your code is that you have one variable keeping track of the clicked state of multiple button elements.
The way to fix this is to add state to the element itself essentially giving multiple variables for multiple elements.
I'm doing this by adding an event object to the callback of the click handler and getting event.currentTarget. The value of event.currentTarget is the element object being clicked. You can add state to this object just like you'd add state to another other javascript object
event.currentTarget.clicked = true;
Now you can keep track of the state for each element!
// just some simple code to get your template in pure JS, don't worry about the code here
const range = [0,1,2,3,4,5];
const template = `<div class="panel-footer" id="loop">
<ul class="post-action">
${range.map(i => `
<button class="btn btn-success guess" id="${i}" value="${i}">${i}</button>
`)}
</ul>
</div>`;
const div = document.createElement('div');
div.innerHTML = template;
document.body.appendChild(div);
// here are where the changes start
// var clicked = true; instead of having a global variable to keep track of the state of all your buttons
$(".guess").click(function(event) {
// you need local state attached to the button
// here we're getting the button element being clicked
const currentTarget = event.currentTarget;
xyz = this.id
console.log(xyz);
// if clicked is truthy
if (currentTarget.clicked) {
$('#' + this.id).css('background-color', '#FF8E2B');
currentTarget.clicked = false;
} else {
$('#' + this.id).css('background-color', '#27AE60');
// set on the element some state
currentTarget.clicked = true;
}
});
.guess {
/* start out in the orange state */
background-color: #FF8E2B;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

What is the easiest way to get the id of a child element?

I have an up-vote button that has an child element with a dynamic id. How can I fetch the id of that child element?
I'm trying to add a voting feature to a blog site, and each blog has a unique ID that I need for the ajax call to log the vote in the database and also to update the vote tally in the html.
$(".plus").click(function() {
var myvar = $(".plus").find("h4");
console.log(myvar);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class='plus'>
<h4>up</h4>
<h3 id='{{blog.id}}'>0</h3>
</button>
Provided you want to get the id of h3 element and print it out in myvar
Check this link
$(".plus").click(function(){
var myvar = $( ".plus" ).find( "h3" ).attr("id");
console.log(myvar);
});
jQuery .children() will be the best option:-
$(".plus").click(function(){
var myvar = $( ".plus" ).children( "h3" ).attr('id');
console.log(myvar);
var myvar1 = $( ".plus" ).children( "h4" ).attr('id');
console.log(myvar1);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class='plus'>
<h4 id="h4_id">up</h4>
<h3 id='h3_id'>0</h3>
</button>
Why .children() is best in your case:- https://stackoverflow.com/a/648014/4248328
Although you can use this to get the child element's id:
$(".plus").click(function() {
var myvar = $(this).find("h3")[0].id;
console.log(myvar);
});
Yet i feel that if you change your markup a little that can also be possible with some data-* attributes:
$('.plus').click(function(){
// jquery version
var blogId = $(this).data('blogId');
console.log("jq .data() version::::", blogId);
// js version
var blgId = this.dataset.blogId;
console.log("js .dataset version::::", blgId);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class='plus' data-blog-id='{{blog.id}}'>
<h4>up</h4>
<h3 id='{{blog.id}}'>0</h3>
</button>
you can use it like this.
$(".plus").click(function() {
var myvar = $(this).find("h3").attr("id");
alert(myvar);
});
If you have multiple .plus items and want to get the id of each one on click, you can use the this context.
$(".plus").click(function() {
var myvar = $(this).find("h4").text();
var myid = $(this).find("h3").attr("id");
console.log(myvar, myid);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class='plus'>
<h4>up</h4>
<h3 id='id_1'>0</h3>
</button>
<button class='plus'>
<h4>down</h4>
<h3 id='id_2'>0</h3>
</button>
With this code, when you click a .plus button, it will look itself for the value of the <h4> snippet and the id of the <h3>.
Using a $(".plus") selector instead of this inside the click function will select ALL the buttons in the page when you click one, and the attr() method will return only the first ID instead of the current one.

How to assign a javascript function by classname

I have multiple buttons (generated by php) for a shopping cart application:
<button class="addtocart" id="<?php echo $code; ?>">
<span id="addtocartbutton">Add to cart</span>
</button>
I want to update my cart using a function:
function AddtoCart() {
alert("Added!");
}
Later, I want to find the id ($code) created by the button which called it (not sure how to do that also, but maybe that's another question). And so I tried this:
document.getElementsByClassName("addtocart").addEventListener("click", AddtoCart());
But it doesn't work. It was working using an onclick, but I understand that the right way to do it by creating an EventListener. Also, I cannot use the on() function in jQuery, because I am forced to use jQuery Version 1.6 which does not have it.
I have looked at https://stackoverflow.com/a/25387857/989468 and I can't really assign it to the parent which is a p tag, because I obviously don't want the other elements in the p tag to be assigned this function.
While the answers given are correct, there is another way: Event Delegation
Attach the listener to a SINGLE thing, in this case the document body and then check to see what element was actually clicked on:
Warning: Typed on the fly: Untested
// Only needed *once* and items may be added or removed on the fly without
// having to add/remove event listeners.
document.body.addEventListener("click", addtoCart);
function addtoCart(event) {
var target = event.target;
while(target) {
if (target.classList.contains('addtocart')) {
break;
}
// Note: May want parentElement here instead.
target = target.parentNode;
}
if (!target) {
return;
}
var id = target.dataset.id;
alert(id + " added!");
}
You should attach click event to every element with class addtocart, since getElementsByClassName() return an array of all objects with given class name so you could use for to loop through everyone of them and associate it with function you want to trigger on click (in my example this function called my_function), check example bellow :
var class_names= document.getElementsByClassName("addtocart");
for (var i = 0; i < class_names.length; i++) {
class_names[i].addEventListener('click', my_function, false);
}
Hope this helps.
function my_function() {
alert(this.id);
};
var class_names= document.getElementsByClassName("addtocart");
for (var i = 0; i < class_names.length; i++) {
class_names[i].addEventListener('click', my_function, false);
}
<button class="addtocart" id="id_1">button 1</button>
<button class="addtocart" id="id_2">button 2</button>
<button class="addtocart" id="id_3">button 3</button>
<button class="addtocart" id="id_3">button 4</button>
I'll show some of the errors you had in your code, then I'll show you how can you improve it so that you can achieve what you want, and I also show that it works with buttons dynamically added later:
First and foremost, you need to pass the function reference (it's name) to the addEventListener! You have called the function, and passed whatever it returned. Instead of:
document.getElementsByClassName("addtocart").addEventListener("click", AddtoCart());
It should've been:
document.getElementsByClassName("addtocart").addEventListener("click", AddtoCart);
Second: document.getElementsByClassName("addtocart") returns a NodeList, you can't operate on it, you need to operate on it's elements: document.getElementsByClassName("addtocart")[0], [1],....
Third, I would suggest you to use the data-... html attribute:
<button class="addtocart" id="addtocart" data-foo="<? echo $code; ?>">
This way you can pass even more data. Now you can get the $code as:
document.getElementById('addtocart').dataset.foo
// el: the button element
function AddtoCart(el) {
// this is the id:
var id = el.id;
// and this is an example data attribute. You can have as many as you wish:
var foo = el.dataset.foo;
alert(id + " (" + foo + ") added!");
}
// Try add a div or something around the area where all the buttons
// will be placed. Even those that will be added dynamically.
// This optimizes it a lib, as every click inside that div will trigger
// onButtonClick()
document.getElementById("buttons").addEventListener("click", onButtonClick);
// this shows that even works when you dynamically add a button later
document.getElementById('add').onclick = addButton;
function addButton() {
var s = document.createElement("span");
s.text = "Add to cart";
var b = document.createElement("button");
b.innerHTML = 'Third <span class="addtocartbutton">Add to cart</span>';
b.className = "addtocart";
b.id="third";
b.dataset.foo="trio";
// note the new button has the same html structure, class
// and it's added under #buttons div!
document.getElementById("buttons").appendChild(b);
}
// this will gett triggered on every click on #buttons
function onButtonClick(event) {
var el = event.target;
if (el && el.parentNode && el.parentNode.classList.contains('addtocart')) {
// call your original handler and pass the button that has the
// id and the other datasets
AddtoCart(el.parentNode);
}
}
<div id="buttons">
<button class="addtocart" id="first" data-foo="uno">First <span class="addtocartbutton">Add to cart</span></button>
<button class="addtocart" id="second" data-foo="duo">Second <span class="addtocartbutton">Add to cart</span></button>
</div>
<button id="add">Add new button</button>
<html>
<head>
<script>
window.onload=function{
var btn = document.getElementsByName("addtocartbtn")[0];
btn.addEventListener("click", AddtoCart());
}
function AddtoCart() {
alert("Added!");
}
</script>
</head>
<body >
<button class="addtocart" name ="addtocartbtn" id="<?php echo $code; ?>" > <span id="addtocartbutton">Add to cart</span></button>
</body>
</html>
Actually class in Javascript is for multiple selection you should provide index like an array.
<button class="addtocart"> <span id="addtocartbutton">Add to cart</span></button>
<script type="text/javascript">
document.getElementsByClassName("addtocart")[0].addEventListener("click", AddtoCart);
function AddtoCart() {
alert("Added!");
}
</script>
Also your second parameter was wrong don't use parentheses.
Applying parentheses means it will call the function automatically when loaded, and will not call the function after that.

Categories

Resources