Closure function is appending all index from loop - javascript

I am trying to append index value to element using the loop. i made a closure to avoid the multiple index appended.
but my closure function still adding the multiple(previous) index to dom
var $newdiv = $('.div').clone().removeClass('div').addClass('show')
$col = $('<div />');
var add = function () {
for(var i=1; i<=10; i++){
(function x (n) {
return function () { //not working!
$newdiv.find($('a span').append(n)).end().clone().appendTo($col);
}();
}(i));
}
}
$col.appendTo('#content');
$('button').click(function () { add()});
$('#content').slimScroll({});
Live

I updated my code like this. it works fine.
var $newdiv = $('.div').clone().removeClass('div').addClass('show')
$col = $('<div />');
var n = 0;
var add = function () {
for(var i=1; i<=10; i++){
$newdiv.clone().removeClass('div').addClass('show')
.find('span').append(n = n < 9 ? '0'+(++n) : ++n).end().clone().appendTo($col);
}
}
$col.appendTo('#content');
$('button').click(function () { add()});
$('#content').slimScroll({});

Related

How get next element after "this" - pure javascript

I have code:
var links = document.querySelectorAll('a[data-lightbox]');
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click', function() {
event.preventDefault();
var imgLink = this.getAttribute('href');
var imgTitle = this.getAttribute('title');
var dataLightbox= this.getAttribute('data-lightbox');
console.log(); //next element after "this." something like "links[i+1]" or i don't know...
}, false);
}
I want to get 'data-lightbox' attribute for next element which I clicked currently. How to do it?
Using a IIFE can do the trick to preserve the i scope
var links = document.querySelectorAll('a[data-lightbox]');
for (var i = 0; i < links.length; i++) {
(function(i){
links[i].addEventListener('click', function() {
event.preventDefault();
var imgLink = this.getAttribute('href');
var imgTitle = this.getAttribute('title');
var dataLightbox= this.getAttribute('data-lightbox');
console.log(links[i + 1]);
}, false);
})(i)
}
This is a scope issue.
You can use bind (which would fix the scope issue) for the onclick event binding,while this you can send i to the method and you can access the next element using i+1
check the following snippet
window.onload = function() {
var links = document.querySelectorAll('a[data-lightbox]');
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click', onclick.bind(links[i], i));
}
function onclick(i) {
var imgLink = this.getAttribute('href');
var imgTitle = this.getAttribute('title');
var dataLightbox = this.getAttribute('data-lightbox');
if(links[i+1]!=undefined){
var nextLightbox = links[i + 1].getAttribute('data-lightbox');
}
console.log(imgLink);
console.log(dataLightbox);
console.log(nextLightbox);
}
}
<a href="#" data-lightbox=10>link1</a>
<a href="#" data-lightbox=20>link2</a><a href="#" data-lightbox=30>link3</a><a href="#" data-lightbox=40>link4</a><a href="#" data-lightbox=50>link5</a>
Hope it helps
You can try to get the next element in the way you thought: links[i + 1], although the i is an unique hoisted variable by this loop. You can, however, re-generate this i in the loop body, using variable declaration of let (only supported in ES6+) or using a new function scope inside that loop.
let acts like we were in a new scope, but not. It won't affect the previous i in this example, it'll only replace its presence at the block statement.
var links = document.querySelectorAll('a[data-lightbox]');
for (var i = 0; i < links.length; i++) {
let i = i;
links[i].addEventListener('click', function() {
event.preventDefault();
var imgLink = this.getAttribute('href');
var imgTitle = this.getAttribute('title');
var dataLightbox= this.getAttribute('data-lightbox');
console.log(links[i + 1]);
}, false);
}
In addition to what others have mentioned, another way to go about this is using nextSibling on this.
var links = document.querySelectorAll('a[data-lightbox]');
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click', function() {
event.preventDefault();
var imgLink = this.getAttribute('href');
var imgTitle = this.getAttribute('title');
var dataLightbox= this.getAttribute('data-lightbox');
console.log(this.nextElementSibling);
}, false);
}

How to ssign Variable with div element's name

So I got multiple divs with different images embedded. Each one has its unique name attributes. I'm trying to apply the hover effect to each divs by changing the image source. I don't want to write multiple scripts, rather I'm trying to write a just one block of script that would effect every div.
<div id="div1" >
<img id="img1" name="img1" src="img1_up.jpg" />
</div>
<div id="div2">
<img id="img2" name="img2" src="img2_up.jpg" />
</div>...and so on
Now here is the script that I currently have for the rollover effects
<script>
var var1 = document.getElementById("div1");
var1.addEventListener("mouseover", changeImage1);
var1.addEventListener("mouseout", restoreImage1);
function changeImage1() {
document.getElementById("img1").src = "img1_ro.jpg";
}
function restoreImage1() {
document.getElementById("img1").src = "img1_up.jpg";
}
var var2 = document.getElementById("div2");
var2.addEventListener("mouseover", changeImage2);
var2.addEventListener("mouseout", restoreImage2);
function changeImage2() {
document.getElementById("img2").src = "img2_ro.jpg";
}
function restoreImage2() {
document.getElementById("img2").src = "img2_up.jpg";
}...and so on
</script>
I would like to use the name attributes from each images to create dynamic code to apply to all images. Here is what I have in mind but not sure the exact way to write it. PLEASE HELP
...
var dynamicVar = ????
dynamicVar.addEventListener("mouseover", changeImage();
dynamicVar.addEventListener("mouseout", restoreImage();
function changeImage() {
document.getElementById(dynamicVar).src = dynamicVar + "_ro.jpg";
}
function restoreImage() {
document.getElementById(dynamicVar).src = dynamicVar + "_up.jpg";
}
You can use loop to add event, don't need to specify id for each div:
var inputs = document.getElementsByTagName("div");
for(var i = 0; i < inputs.length; i++) {
if(inputs[i].id.indexOf('div') >= 0) {
inputs[i].addEventListener("mouseover", changeImage);
inputs[i].addEventListener("mouseout", restoreImage);
}
}
function changeImage(){
var tmpStr = this.id;
var divIndex = tmpStr.substring(3, tmpStr.length);
document.getElementById("img" + divIndex).src = divIndex + "_ro.jpg";
}
function restoreImage(){
var tmpStr = this.id;
var divIndex = tmpStr.substring(3, tmpStr.length);
document.getElementById("img" + divIndex).src = divIndex + "_up.jpg";
}
See on fiddle: Link
try this
var parent = document.getElementById("parent");
var childs = parent.getElementsByTagName('div');
for (var i = 0; i < childs.length; i++) {
(function () {
var e = childs[i];
e.addEventListener("mouseover", function () {
changeImage(e);
});
e.addEventListener("mouseout", function () {
restoreImage(e);
});
}());
}
function changeImage(element) {
var imgs = element.getElementsByTagName('img');
for (var i = 0; i < imgs.length; i++) {
alert(imgs[i].id);
}
}
function restoreImage(element) {
var imgs = element.getElementsByTagName('img');
for (var i = 0; i < imgs.length; i++) {
imgs[i].src = img_ro;
}
}
you can check this fiddle

Setting onclick function to <li> element

I am trying to dynamically add onclick function to "li" tagged elements.
But the event does not fires.
Here is my code:
var arrSideNavButtons = [];
var sideNavLi = document.getElementsByClassName('side-nav')[0].getElementsByTagName('li');
var arrayOfSceneAudios = [scene1Audio, scene2Audio,...];
for (var i = 0; i < sideNavLi.length; i++) {
sideNavLi[i].onclick = function() {
arrayOfSceneAudios[i].play();
}
arrSideNavButtons.push(sideNavLi[i]);
}
Is it possible to code it this way?
If yes, what is my mistake?
Thanks a lot.
Wrap your onclick handler in a closure, else it only get assigned to the last elem in the loop:
for (var i = 0; i < sideNavLi.length; i++) {
(function(i) {
sideNavLi[i].onclick = function() {
arrayOfSceneAudios[i].play();
}
arrSideNavButtons.push(sideNavLi[i]);
})(i)
}
I think it's better to reuse one single function, instead of creating a new one at each iteration:
var arrSideNavButtons = [],
sideNavLi = document.getElementsByClassName('side-nav')[0].getElementsByTagName('li'),
arrayOfSceneAudios = [scene1Audio, scene2Audio,...],
handler = function() {
this.sceneAudio.play();
};
for (var i = 0; i < sideNavLi.length; i++) {
sideNavLi[i].sceneAudio = arrayOfSceneAudios[i];
sideNavLi[i].onclick = handler;
arrSideNavButtons.push(sideNavLi[i]);
}

Find index in array different from the array that loaded

Line 35, just before the alert, returns -1. I also tried $(this).index() with the same result. Here is what it should do: Clicking EN.gif should return 4, then grand_array_pics[4] should give me en_array_pics and load the .gifs in that array.
$(document).ready(function () {
var main_pics = ["AN.gif", "BN.gif", "CN.gif", "DN.gif", "EN.gif", "GN.gif"];
var starting_pics = ["AN.gif", "CN.gif", "EN.gif"];
var an_array_pics = ["BN.gif", "EN.gif", "GN.gif", "AN.gif","DN.gif"];
var bn_array_pics = ["CN.gif", "DN.gif", "GN.gif"];
var cn_array_pics = ["DN.gif", "GN.gif", "AN.gif", "CN.gif"];
var dn_array_pics = ["EN.gif", "AN.gif", "CN.gif"];
var en_array_pics = ["GN.gif", "AN.gif", "CN.gif", "EN.gif"];
var gn_array_pics = ["AN.gif", "CN.gif", "EN.gif", "GN.gif"];
var grand_array_pics = [
an_array_pics,
bn_array_pics,
cn_array_pics,
dn_array_pics,
en_array_pics,
gn_array_pics
];
var i = 0;
for (i = 0; i < starting_pics.length; i++) {
$("<img/>").attr("src", "images/" + starting_pics[i]).load(function () {
$(this).appendTo("#main");
$(this).addClass("pics");
});
}
$("#main").on("click", ".pics", function () {
var j = $.inArray(this, main_pics);
alert(j);
$("#sidebar .pics").remove();
$(this).clone().appendTo("#train");
$(this).clone().appendTo("#sidebar");
$("#main .pics").remove();
var chosen_pics_array = grand_array_pics[j];
var count = chosen_pics_array.length;
var k = 0;
for (k = 0; k < count; k++) {
$("<img/>").attr("src", "images/" + chosen_pics_array[k]).load(function () {
$(this).appendTo("#main");
$(this).addClass("pics");
});
}
});
}); //end ready
this is the DOM <img> element, while main_pics is an array of strings. It will never be found inside there. Use
var j = $.inArray(this.src.split("/").pop(), main_pics);
Give this a try. You need to get the name of the file and you're passing the element itself into $.inArray
var j = $.inArray(this.src.substring(this.src.lastIndexOf('/')+1), main_pics);

Problems with multidimensional array and loops

This script crashes randomly with the message "unable to get property .length of undefined or null reference" referring to "matched_array_pics.length". It crashes for sure if I clone, append the same image twice to the #train div.
$(document).ready(function () {
var starting_pics = ["AN.gif", "CN.gif", "EN.gif", "GN.gif"];
var an_array_pics = ["CN.gif", "EN.gif", "GN.gif", "AN.gif"];
var cn_array_pics = ["EN.gif", "GN.gif", "AN.gif", "CN.gif"];
var en_array_pics = ["GN.gif", "AN.gif", "CN.gif", "EN.gif"];
var gn_array_pics = ["AN.gif", "CN.gif", "EN.gif", "GN.gif"];
var grand_array_pics = [an_array_pics, cn_array_pics, en_array_pics, gn_array_pics];
var i = 0;
for (i = 0; i < starting_pics.length; i++) {
$("<img/>").attr("src", "images/" + starting_pics[i]).load(function () {
$(this).appendTo("#main");
$(this).addClass("pics");
});
}
$("#main").on("click", ".pics", function () {
var j = $(".pics").index(this); // gets the index for the matched_array_pics...
console.log(j);
$("#sidebar .pics").remove();
$(this).clone().appendTo("#train");
$(this).clone().appendTo("#sidebar");
$("#main .pics").remove();
var matched_array_pics = grand_array_pics[j]; // ... in grand_array_pics.
var k = 0;
for (k = 0; k < matched_array_pics.length; k++) {
$("<img/>").attr("src", "images/" + matched_array_pics[k]).load(function () {
$(this).appendTo("#main");
$(this).addClass("pics");
});
}
});
}); //end ready
I think the problem is in this line: var j = $(".pics").index(this); and I think it should be rewritten like this: var j = $(this).index(); It'd be helpful if you could add console.log(j); just after the line in question to see what j ends up being. When this line executes var matched_array_pics = grand_array_pics[j]; I think you're getting undefined because j is not a number when your code runs.

Categories

Resources