Dynamically bond handler on multiple elements will call only last bond function - javascript

http://jsfiddle.net/7CV88/8/
On this snippet, I try to bind change to #r(Nth)e <input> element to change the contents of #r(N+1th)s <input> element. But when I change any Nth <input> element, the message shown is always "#r(last N)e change handler"
for(var i = 1; i < numRanges; i++){
$('#r'+i+'e').change(function(){
$('#messages').html('#r'+i+'e change handler');
$('#r'+(i+1)+'s').val($('#r'+i+'e').val());
});
}

You should use the so-called event data to pass the value of i into the onchange event handler:
for(var i = 1; i < numRanges; i++){
$('#r'+i+'e').change(i, function(e){
$('#messages').html('#r'+e.data+'e change handler');
$('#r'+(e.data+1)+'s').val($('#r'+e.data+'e').val());
});
}
Updated Demo.
Note: This just answers directly to your asked problem, I know your code is messy, fixing it is not the main thing to do.

This is a typical "closure" issue.
I was trying the simplest way to get out of the closure issue so I suggested this incorrect way:
for(var i = 1; i < numRanges; i++){
$('#r'+i+'e').change(function(){
var tempVariable = i;
$('#messages').html('#r'+tempVariable +'e change handler');
$('#r'+(tempVariable +1)+'s').val($('#r'+tempVariable +'e').val());
});
}
Thanks to metadings, I realized my mistake so I created a demo to test according to their advice:
var list = $("div");
for(var i = 0; i < list.length; i++){
$(list[i]).click((function(x){
return function(){alert(x);};
})(i));
}
http://jsfiddle.net/9qBXn/
HTH

Related

index number for the line time using JavaScript

I am using the below code in the google tag manager custom JavaScript variable, but it returns same index value for every line item, what can be the issue?
Web page link: https://www.amity.edu/programe-list.aspx?fd=all
function() {
var elements = document.querySelectorAll('.staff-container');
for (var i = 0; i < elements.length; i++){
(function(index){
elements[i].children[0].children[0].addEventListener("click", myScript);
function myScript(){
return("Clicked : ",index);
}
})(i);
}
}
There is an error in the 5th line.
It should be elements[index].children... in that case.
The updated code:
function() {
var elements = document.querySelectorAll('.staff-container');
for (var i = 0; i < elements.length; i++){
(function(index){
elements[index].children[0].children[0].addEventListener("click", myScript);
function myScript(){
return("Clicked : ",index);
}
})(i);
}
}
Here is an alternative way from Simo's blog
Blog link
Although the post is say about visibility element. I test it with click on my website.
This might work
function() {
var list = document.querySelectorAll('.staff-container a'),
el = {{Click Element}};
return [].indexOf.call(list, el) + 1;
}
If it is not working, you might need to provide the screenshot about the click element from your GTM preview.

button OnClick event not firing

There is a page and I am trying to attach an onclick event to the button ("SEARCH CRUISES") on the page but the onclick event is not firing correctly. Here is my code:
<script>
debugger;
var x = document.getElementsByClassName("cdc-filters-search-cta")
for (i=0; i< x.length; i++){
if(x[i].text.trim().indexOf("SEARCH") >= 0 && x[i].text.trim().indexOf("CRUISES") >= 0){
x[i].onclick = function(){
console.log("Search button clicked");
};
break;
}
}
Here is the complete html: https://jsfiddle.net/g0tkqrx6/
I have tried attaching the onclick event to the object in many different ways but I am not able to get the click event to fire. I would appreciate if anybody can provide some insight as to what I could be doing wrong here.
Thanks in advance
Seeing your html would be helpful. Make sure you are interacting with the correct names for your js events.
You must use textContent for element text and make it uppercase.
Here is an example:
var x = document.getElementsByClassName("cdc-filters-search-cta")
for (var i=0; i< x.length; i++){
var element = x[i] ;
if((element.textContent ).toUpperCase().indexOf("SEARCH") >= 0 && element.textContent.toUpperCase().indexOf("CARS") >= 0){
element.onclick = function(){
console.log("Search button clicked");
};
break;
}
}
<button class="cdc-filters-search-cta"> SEARCH</button>
<button class="cdc-filters-search-cta"> CARS</button>
<button class="cdc-filters-search-cta">SEARCH CARS</button>
Well to start with I think you should really take a look at this article on why you shouldn't add inline functions or css.
https://www.tomdalling.com/blog/coding-styleconventions/why-inline-comments-are-generally-a-bad-idea/
Secondly I think your issue is that you are trying to add a click event to an angular front end which is controlled by the ngModel and also the site is probably compiled AOT. However you can try this,
let x = document.querySelectorAll('.cdc-filters-search-cta');
let term = /[(SEARCH)(CRUISES)]/
x = Array.from(x);
x.forEach(span => {
if (term.test(span.textContent)) {
return span.addEventListener('click', (e) => {
console.log('span clicked')
});
}
})
I changed your code to querySelectorAll which returns an array and I used a forEach loop to add an eventListener. Not sure how well that will go down with your angular, but maybe.

javascript: set onclick function with a parameter for a button

I have created a button using javascript and now I want to give it a onclick. however I want the function to have a parameter i. the problem is that when I inspect the console the onclick function is just onclick=playAudio(i). I want it to be different for each value of i in the for loop, but because it is in brackets it just stays as i instead of the current number in the for loop. I hope I have explained this properly. some of the code is below to help you understand.
var i;
var audioMp3 = ["audio/Un", "audio/Deux", "audio/Trois", "audio/Quatre", "audio/Cinq", "audio/Six", "audio/Sept", "audio/Huit", "audio/Neuf", "audio/Dix"];
for(i = 0; i < audioMp3.length; i++{
var audioBtn = document.createElement("BUTTON");
audioBtn.setAttribute("onclick", "playAudio(i);";
}
var audioMp3 = ["audio/Un", "audio/Deux", "audio/Trois", "audio/Quatre", "audio/Cinq", "audio/Six", "audio/Sept", "audio/Huit", "audio/Neuf", "audio/Dix"];
for(var i = 0; i < audioMp3.length; i++){
var node = document.createElement("BUTTON");
var textnode = document.createTextNode(audioMp3[i]);
node.appendChild(textnode);
node.setAttribute("onclick", "playAudio("+i+");");
document.getElementById("element").appendChild(node);
}
function playAudio(i){
alert(i);
}
<div id="element"></div>
I'm pretty sure that this should work :
audioBtn.setAttribute("onclick", "playAudio("+i+");");
audioBtn.onclick = function(){
playAudio(i)
}
Create an array with all the possible values, loop through the values to create the buttons, each button should have their click event listener to play their own button's song.
I don't know your precise code but that is the pseudo-code to do it.

Events will not fire that have been added to dynamically created divs

I'm working in JavaScript. For the most part I've been able to add event listeners fine, but for divs that I have generated dynamically whatever event I add to them nothing seems to happen. The code is:
for(var i=0; i<sceneNumber; i++){
var a=i;
if(i>2)
a=i%3;
sceneArray[i]=document.createElement('div');
sceneArray[i].className="border"+a;
if(i%2==1)
sceneArray[i].style.left=0;
else
sceneArray[i].style.left=(i+1)*100;
sceneArray[i].style.top = i*100+100;
sceneArray[i].onclick= function(){console.log("fire212");
if(extend1){
console.log("scenelistener");
currentArrow.rotate(degrees);
currentArrow.scale(desiredLength/arrowLength,1);
}
};
console.log(sceneArray[i].onclick);
document.getElementsByTagName('body')[0].appendChild(sceneArray[i]);
sceneArray[i].style.zIndex = -1;
console.log(sceneArray[i]);
}
As you can see I should at least get "fire212" in the console but even that doesn't happen. What could be going wrong?
You should implement something similer to JQuery's live() or on() methods. The below post may help you.
http://www.alfajango.com/blog/exploring-jquery-live-and-die/
for(var i=0; i<sceneNumber; i++){
var a=i;
if(i>2)
a=i%3;
sceneArray[i]=document.createElement('div');
sceneArray[i].className="border"+a;
if(i%2==1)
sceneArray[i].style.left=0;
else
sceneArray[i].style.left=(i+1)*100;
sceneArray[i].style.top = i*100+100;
sceneArray[i].onclick=onclickevent();
console.log(sceneArray[i].onclick);
document.getElementsByTagName('body')[0].appendChild(sceneArray[i]);
sceneArray[i].style.zIndex = -1;
console.log(sceneArray[i]);
}
function onclickevent(){
console.log("fire212");
if(extend1){
console.log("scenelistener");
currentArrow.rotate(degrees);
currentArrow.scale(desiredLength/arrowLength,1);
}
}

Javascript - Dynamically assign onclick event in the loop

I have very simple html page with js code:
<html>
<head>
<title></title>
</head>
<body>
<div id="divButtons">
</div>
<script type="text/javascript">
var arrOptions = new Array();
for (var i = 0; i < 10; i++) {
arrOptions[i] = "option" + i;
}
for (var i = 0; i < arrOptions.length; i++) {
var btnShow = document.createElement("input");
btnShow.setAttribute("type", "button");
btnShow.value = "Show Me Option";
var optionPar = arrOptions[i];
btnShow.onclick = function() {
showParam(optionPar);
}
document.getElementById('divButtons').appendChild(btnShow);
}
function showParam(value) {
alert(value);
}
</script>
</body>
</html>
That page binds 10 buttons, but when you click on any button it always shows alert "option9". How is it possible assign onclick event to show correspondent option !?
Thanks!
You'll have to do something like this:
btnShow.onclick = (function(opt) {
return function() {
showParam(opt);
};
})(arrOptions[i]);
Consider the fact that when the onclick() function is executed, all it has is:
showParam(optionPar);
, verbatim. The optionPar will be resolve at the time the click event is executed, and at this point it most likely be the latest value you assigned to it. You should generally avoid passing variables in such a way.
The problem you are trying to solve is best solved by re-writing the piece such as:
btnShow.value = "Show Me Option";
var optionPar = arrOptions[i];
btnShow.optionPar = optionPar;
btnShow.onclick = function(e) {
// if I'm not mistaking on how to reference the source of the event.
// and if it would work in all the browsers. But that's the idea.
showParam(e.source.optionPar);
}
The accepted answer seems to work, but seems to be confusing and a somewhat cumbersome way to do it. A better way perhaps might be to use the data attribute for the element you're looking to assign the event listener for. It's simple, easy to understand, and way less code. Here's an example:
btnShow.data = arrOptions[i];
btnShow.onclick = function() {
showParam(this.data);
}
I attach an event handler:
window.onload = function() {
var folderElement;
tagFolders = document.getElementById("folders");
for (i = 0; i < folders.length; i++) {
folderElement = folderButtons[i];
folderElement = document.createElement("button");
folderElement.setAttribute("id", folders[i]);
folderElement.setAttribute("type", "button");
folderElement.innerHTML = folders[i];
if (typeof window.addEventListener !== "undefined") {
folderElement.addEventListener("click", getFolderElement, false);
} else {
folderElement.attachEvent("onclick", getFolderElement);
}
tagFolders.appendChild(folderElement);
}
which can retrieve anything from the element that triggered the event:
// This function is the event handler for the folder buttons.
function getFolderElement(event) {
var eventElement = event.currentTarget;
updateFolderContent(eventElement.id);
}
in which case you have to embed the option inside the element / tag. In my case I use the id.
For jquery, check out the adding event data section from the API:
...
for (var i = 0; i < arrOptions.length; i++) {
$('<input id="btn" type="button" value="Show Me Option"><input>').appendTo("#divButtons")
$('#btn').bind("click", {
iCount: i},
function(event) {
showParam(arrOptions[iCount]);
});
}
The accepted answer is correct but I feel that no real explanation was done.
Let me try to explain, the issue here is classical missing closure.
The variable 'i' is getting increased by 1 per loop iteration,
and the on-click event actually is not being executed, whether only applied to the a element, it getting summarize up to the length of arrOptions which is 10.
So, the loop continues up until 'i' is 10,
Then, whenever the on-click event is being triggered, it takes the value of i which is 10.
now, for the solution,
in the solution we are using a closure, so that when we apply the value of 'i' to the on-click event of the a element, it actually gets the exact value of i at in time.
The inner function of the onclick event create a closure where it references the parameter (arrOptions[i]), meaning what the actual i variable is at the right time.
The function eventually closes with that value safely,
and can then return its corresponding value when the on-click event is being executed.
You pass just the reference of the variable to the function, not it's value. So every time the loop is iterated, it assigns a reference to your anonymous function and all of them point to the same value in memory. But since you use the same variable name in the loop, you overwrite the value of the variable. You can concatenate the variable to a string to preserve it's value. For example like that:
btnShow.onclick = new Function("", "showParam(" + arrOptions[i] + ");");
The first parameter is the name of the function but afaik it is optional (it can be left blank or omitted at all).
pp();
function pp()
{
for(j=0;j<=11;j++)
{
if(j%4==0)
{
html+= "<br>";
}
html += "<span class='remote' onclick='setLift(this)' >"+ j+"</span>";
}
document.getElementById('el').innerHTML = html;
}
function setLift(x)
{
alert(x.innerHTML);
}

Categories