Cannot properly create rollover on dynamically created html element - javascript

I created some buttons dynamically based on loop over an array of names, then I want to add rollover actions on these buttons, but the alert() in this code always prints the name of the last item (black).
I tried using eval() on that alert() part but it didn't make any difference.
I expect it to return red, green or black depending on which button I hover the mouse.
<div id="channels_buttons_container">
</div>
<script>
channels_array = ["red", "green", "black"];
for(var i = 0; i < channels_array.length; i++) {
loop_channel_name = channels_array[i];
// append an element inside the container
var new_button_element = document.createElement("span");
new_button_element.id = 'channel_button_'+loop_channel_name;
new_button_element.innerHTML = '<br>BLA BLA';
document.getElementById('channels_buttons_container').appendChild(new_button_element);
// try to add rollover actions on the new button
document.getElementById('channel_button_'+loop_channel_name).onmouseover = function(){
alert('Rollover '+loop_channel_name);
}
}
</script>

the code it's ok but when you use "loop_channel_name" take the last element of array. You must pass the actual element (this):
document.getElementById('channel_button_'+loop_channel_name).onmouseover = function(){
alert('Rollover '+this.id);
}
Example

loop_channel_name is initialized as a global variable because you didn't use the var keyword. Try var loop_channel_name instead of just loop_channel_name. When you initialize loop_channel_name on the first iteration of the for loop you are creating it as a global variable and on subsequent iterations you are just updating that instead of creating a new reference. By referring to loop_channel_name in the alert you are referencing the global variable which was updated to black on the last iteration of the loop, hence it always alerting black.
Example
<div id="channels_buttons_container">
</div>
<script>
channels_array = ["red", "green", "black"];
for(var i = 0; i < channels_array.length; i++) {
var loop_channel_name = channels_array[i];
var new_button_element = document.createElement("span");
new_button_element.id = 'channel_button_'+loop_channel_name;
new_button_element.innerHTML = '<br>BLA BLA';
document.getElementById('channels_buttons_container').appendChild(new_button_element);
document.getElementById('channel_button_'+loop_channel_name).onmouseover = function(){
alert('Rollover '+loop_channel_name);
/*You could also do*/
alert('Rollover '+ channels_array[i]);
}
//
}
</script>

Related

Is there any way to cyclically update only a <div> content in pure Javascript?

I'm using a div with a <li> element inside where I add some dynamically created elements (localStorage keys to be more specific). I want to update the div every "x" seconds but only the <div>, not the whole page. I know that it can be done with Ajax and JQuery ($( "#here" ).load(window.location.href + " #here" );).
But is there any way to do this whit pure js?
UPDATE
The specific case is that im picking all the localstorage keys and appending them to a list inside a div. When i use like this (window.onload) it works fine. But I want to update it cyclically. If i use a "setinterval" or a button to call the function the previous keys appends repeatedly. (like: file 1.... then: file 1, file 1 file 2 ... then: file 1 file 1 file 2 file 1 file 1 file 1 file 2 file 3)
window.onload = function cargararchivos() {
localstorage = []
var keys = Object.keys(localStorage);
for (let i = 0; i < keys.length; i++) {
var elemento_lista = document.createElement('li')
elemento_lista.innerHTML = keys[i]
var lista = document.getElementById('lista_archivos')
lista.appendChild(elemento_lista)
localstorage[ keys[i] ] = localStorage.getItem( keys[i] )
elemento_lista.onclick = function()
{alert(JSON.parse(localStorage[keys[i]]))}}
};
This can be done using the setInterval function. It executes a function of your choice after a pre-determined amount of time.
To do this your DIV must have an unique ID, so we can access it using Javascript's getElementById() method.
Here's a simple example, which updates a div with the current time every 1000 milliseconds:
function update() {
document.getElementById("myDiv").innerHTML = new Date();
}
var interval = setInterval(update, 1000);
<div id="myDiv">
</div>
The reason your method works the first time, but doesn't work after that is because the method adds DOM nodes. After the second call, you're seeing DOM nodes from both the first call and second call. After the third call, you'd see nodes from the first, second, and third calls... and so on.
If you want to repeatedly call a method like cargararchivos() that adds DOM nodes, you must first remove any DOM elements that have been previously added. I've updated your code, assuming lista_archivos starts empty (no child elements):
function cargararchivos() {
localstorage = []
var keys = Object.keys(localStorage);
var lista = document.getElementById('lista_archivos')
// Ensure any previously added DOM nodes are removed.
while (lista.firstChild) {
lista.removeChild(lista.firstChild);
}
for (let i = 0; i < keys.length; i++) {
var elemento_lista = document.createElement('li')
elemento_lista.innerHTML = keys[i]
lista.appendChild(elemento_lista)
localstorage[ keys[i] ] = localStorage.getItem( keys[i] )
elemento_lista.onclick = function()
{alert(JSON.parse(localStorage[keys[i]]))}
}
};

And how to click on the same button to return everything back?

When the button is clicked, I change the values of the display to the elements, change the color and the values of the input.
var deleteMarkerButton = document.getElementById('deleteMarkerButton');
var chooseMarkerDelete = document.getElementsByClassName('choose-marker__delete');
var chooseMarkerCheckbox = document.getElementsByClassName('choose-marker__checkbox');
var changeBasketColor = document.getElementsByClassName('cls-2');
deleteMarkerButton.addEventListener("click", function () {
for (var i = 0; i < chooseMarkerDelete.length; i++) chooseMarkerDelete[i].style.display = 'block';
for (var a = 0; a < chooseMarkerCheckbox.length; a++) chooseMarkerCheckbox[a].style.display = 'none';
for (var b = 0; b < changeBasketColor.length; b++) changeBasketColor[b].style.fill = '#3c8bca';
document.getElementById("addDeleteBtn").value = "Удалить";
});
If you're always toggling between the same two values, this is trivial: just check to see what the current value is, and replace it with the other value. Pseudocode if (foo === a) {foo = b} else {foo = a}
If you need to be able to revert to the original values after changing something, and the original values aren't known ahead of time, then you need to store those original values somewhere before changing them.
Below is a simplified example of one way to do this.
This toggles an element's style.display. The current value is stored in a data attribute on the element before it's modified; that way the next time you click, the function can check the data attribute to see what the previous value was:
var foo = document.getElementById("foo");
var bar = document.getElementById("bar");
foo.addEventListener("click", function() {
// check to see if we've already stashed a value here:
var pastValue = bar.getAttribute("data-display");
// stash the current value:
bar.setAttribute("data-display", bar.style.display);
// set the current style to the stashed value, if there is one, or "none" otherwise:
bar.style.display = pastValue || "none";
});
<div id="foo">Click me</div>
<!-- the inline style is used here because `.style.display` can only read inline rules -->
<div id="bar" style="display:block">This will be toggled</div>

calling function with 2 parameters onclick

I want to call a function from a dynamically created element which contains 2 parameters, but it is sending it as only only parameter by merging the two.
$("#click").click(function(){
var td = document.createElement('div');
var num1 = 10;
var num = 5;
td.innerHTML = "new";
$(td).attr('onclick','updateDistance("'+num1+','+num+'")');
document.getElementById("div1").appendChild(td);
})
function updateDistance(id,distance){
alert(id+","+distance);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
<div id = "div1">
Text here
</div>
<button id = "click">CLick here</button>
please help
That happens because your
$(td).attr('onclick','updateDistance("'+num1+','+num+'")');
Is creating a script like this
updateDistance("10,5")
Is just a string with a comma in the middle. One parameter. You want to create this:
updateDistance("10","5")
So for this you have to do it this way:
$(td).attr('onclick','updateDistance("'+num1+'","'+num+'")');
Notice where I added the quotes.
By the way, being numbers, you can avoid the quotes:
$(td).attr('onclick','updateDistance('+num1+','+num+')');
And this will create this:
updateDistance(10,5)
So they are passed as numbers, not strings. There's a big difference between "10" and 10 (without quotes).
Also, you can attach a click event that will call the function directly, without any hack:
$(td).on('click', function() { updateDistance(num1, num); });
And if you are creating a lot of elements and having problems with the variables values outside the click context, check this answer I recently written: https://stackoverflow.com/a/42283571/1525495
You just have to call it inside a function:
Change
$(td).attr('onclick','updateDistance("'+num1+','+num+'")');
To this:
$(td).click(function() {
updateDistance(num1,num);
});
If your two parameters are dynamic, you can have them assigned to the object td and reused.
$("#click").click(function(){
var td = document.createElement('div');
td.id = 10; // or however you calculate this value
td.distance = 5; // or however you calculate it.
td.innerHTML = "new";
$(td).click(function() {
// extract the dynamic value and call the function with it.
var id = this.id;
var distance = $(this).prop("distance");
updateDistance(id,distance);
});
document.getElementById("div1").appendChild(td);
});
Here is a working example:
Demo

Javascript for loop function array

I'm bit of a javascript newbie - I'm trying to make a function that when I click a button it will call out a single object out of my array, in order.
all it does is display "ee".
Of course, you are looping through the whole array and assigning each item to the innerHTML of that one element - and only the last one will stay there and show up.
What I want it to do is when I click the button to display "aa" then when I press it again to display "bb" instead of "aa" and so on.
Then you can't use a for-loop, but have to keep track of the counter manually and execute only one step per invocation of call.
var myArray = ["aa","bb","cc","dd","ee"];
var i=0;
function call() {
document.getElementById("placeDiv").innerHTML = myArray[i];
if (i < myArray.length-1)
i++;
else
i = 0; // restart, but you may as well show an error message
}
You want a closure.
var call = (function() {
var i = 0,
entries = ["aa", "bb", "cc", "dd", "ee"];
return function() {
return entries[i++ % entries.length];
};
})();
This keeps i and entries as private values, and returns a function that goes to the next entry in the list each time it is called.
Try this:-
You are looping through on each click and assigning value to the element innerHTML so it will always have only the last value from the array.
Demo
var myArray = ["aa","bb","cc","dd","ee"];
var i = 0;
function call(){
if(myArray.length <= i) i=0;
document.getElementById("placeDiv").innerHTML = myArray[i++];
}
if you don't want to use a global variable you can use this way too.
http://jsfiddle.net/zZ4Rm/
Use shift method on array to get the first item and then push it back tht end of the array for the cycle to happen.
var myArray = ["aa","bb","cc","dd","ee"];
function call(){
var val = myArray.shift();
myArray.push(val);
document.getElementById("placeDiv").innerHTML = val;
}
You are overwritting your placeDiv with innerHTML.
Try using:
function call(){
var yourVar= document.getElementById('placeDiv');
for (var i=0; i < myArray.length; i++) {
yourVar.innerHTML = yourVar.innerHTML + myArray[i];
}
}
<script type="text/javascript">
var myArray = ["aa","bb","cc","dd","ee"],
num=0;
function call() {
document.getElementById("placeDiv").innerHTML = myArray[num];
num++;
};
</script>
<button onclick="call()">Click!</button>
<div id = "placeDiv"></div>

Can't put search results into Hyperlinks and append to a div

okay i have come across a simple javascript code that will search all the hyperlinks in a page which works briliantly fast. the only problem is that the browser freezes when it tries to remake these links in a div, no error just as soon as i push the button the browser refuses to load. as you can see it gets the input from a form then searches every hyperlink for these terms then is supposed to populate a div with links but it doesn't. the code is as follows.
function search0(){
var lists = document.getElementsByTagName("a");
for (var i = 0; i < lists.length; i++) {
var output = lists[i];
var team1 = document.getElementById("search1").value;
var matchPos1 = output.innerHTML.search(team1);
if(matchPos1 != -1){
var team2 = document.getElementById("search2").value;
var matchPos2 = output.innerHTML.search(team2);
if(matchPos2 != -1){
var elem1 = document.createElement("a")
var styleattr=document.createAttribute("href");
styleattr.nodeValue=output;
elem1.setAttributeNode(styleattr);
var text1 = document.createTextNode(output.innerhtml);
elem1.appendChild(text1);
var parentdiv = document.getElementById("frame2");
parentdiv.appendChild(elem1);
}
}
}
}
You are creating an infinite loop.
The nodeList you create with document.getElementsByTagName("a") is live i.e. if you add a link to the page it will appear in this list automatically! Yes, that's right, even without requerying. Here's a reference doc.
You are adding links to the nodeList which are then matched and added to the end on the nodeList which are then matched and so on and so on
To do what you want to do you should create an initial array of links like this.
//creates a real js array from a nodelist
var list = Array.prototype.slice.call( document.getElementsByTagName("a"), 0 );
Here is an explanation of Array.prototype.slice.call
Also change case-sensitive mistake:
var text1 = document.createTextNode(output.innerhtml);
To
var text1 = document.createTextNode(output.innerHTML);

Categories

Resources