How to loop through eq(i) with variating i? [duplicate] - javascript

This question already has answers here:
Javascript infamous Loop issue? [duplicate]
(5 answers)
Closed 8 years ago.
I have multiple <div class='drop'> with jQuery .slideUp() and .slideDown() attached to them. I would like to use some kind of loop to determine which one of the trigger <span class='more'> was clicked and .slideDown() the corresponding <div>. Here's what I've got so far:
$(document).ready(function(){
var i=0;
$('.more').eq(i).click(function(){
$('.drop').eq(i).slideDown(800) && $('.more').eq(i).hide(300);
});
$(".less").eq(i).click(function(){
$(".drop").eq(i).slideUp(800) && $(".more").eq(i).show(500);
});
});
It works as long as I define i and don't put it in a loop. As soon as it's looped like so:
$(document).ready(function(){
for(var i=0; i<$('.drop').length; i++){
$('.more').eq(i).click(function(){
$('.drop').eq(i).slideDown(800) && $('.more').eq(i).hide(300);
});
$(".less").eq(i).click(function(){
$(".drop").eq(i).slideUp(800) && $(".more").eq(i).show(500);};
});
};
});
It stops working. What am I missing?

Consider the following segment of code:
for(var i=0; i<$('.drop').length; i++){
$('.more').eq(i).click(function(){
$('.drop').eq(i).slideDown(800) && $('.more').eq(i).hide(300);
});
}
When does that anonymous function get called? When one of the .more elements is clicked.
What is the value of i at that point? The loop has finished by the time the element is clicked, so i === $('.drop').length.
So when the anonymous function is called, it's like executing the function:
function(){
var i = $('.drop').length;
$('.drop').eq(i).slideDown(800) && $('.more').eq(i).hide(300);
}
and it's pretty clear that $('.drop').eq($('.drop').length) isn't very useful.
You could fix it by creating a new function with a locally scoped copy of i at each iteration:
for(var i=0; i<$('.drop').length; i++){
$('.more').eq(i).click(function(i) {
return function(){
$('.drop').eq(i).slideDown(800) && $('.more').eq(i).hide(300);
};
}(i));
}
However if all your elements with that class belong to some subtree of the DOM, there is probably a better way using event delegation. Bind to the click handler of the parent of that subtree and then handle it there and use e.target to determine which element was clicked. There is an example of that here.

It is because of the wrong use of a closure variable in a loop, in this case there is no need to use a loop.
jQuery(function ($) {
var $drops = $('.drop');
var $mores = $('.more').click(function () {
$drops.eq($mores.index(this)).slideDown(800) && $(this).hide(300);
})
});

Related

Event listeners not working [duplicate]

the solution to this problem is probably pretty simple, but I need some help.
var x;
for(x in document.getElementsByTagName("img"))
x.addEventListener('click',openPage, false);
function openPage() {
alert("clicked");
}
I'm not getting an alert when I click on an <img src="something" /> tag. Anyone know why? Also, is my loop necessary?
This code produces an error - in a for..in statement, 'x' is the key of your object (in this case, your document.getElementsByTagName call). What you want is:
var x,
imgs = document.getElementsByTagName("img");
for(x in imgs) {
if (imgs[x] instanceof Element) {
imgs[x].addEventListener('click',openPage, false);
}
}
function openPage() {
alert("clicked");
}
Might I suggest using a Javascript framework (like jQuery), which can help simplify your code as such:
$('img').each(function() {
$(this).click(function() {
alert('Clicked!');
// Now that we're in the callback context, $(this) will be the current
// target - the specific image that was clicked.
// i.e. $(this).fadeOut() would slowly fade out the clicked image.
});
});

jQuery .click function is not working? [duplicate]

This question already has answers here:
Event handlers inside a Javascript loop - need a closure?
(2 answers)
Closed 7 years ago.
I have a javaScript file in which i am trying to bind a function named change by using jQuery i tried this code but it is not working?
script.js
for(var i=1; i<suggestionList.length; i++)
{
$list.append("<li>" + suggestionList[i] + "</li>");
// attach handler for click on the suggestions
$list.find("li").eq(i).click(function() {
change(suggestionList[0], suggestionList[i]);
});
}
function change(changeto,changewith)
{
var replaceto=document.getElementById(changeto).innerHTML;
var replacewith=changewith;
var text1=document.getElementById("para").innerHTML;
var afterRe=text1.replace(replaceto,replacewith);
document.getElementById("para").innerHTML=afterRe;
}
please help me why my code is not working?
you can't use i inside the for-loop for click event. I have set a demo jsfiddle here .check If it helps
for(var i=1; i<suggestionList.length; i++)
{
$list.append("<li>" + suggestionList[i] + "</li>");
// attach handler for click on the suggestions
}
$list.find("li").click(function() {
changewith=$(this).html();
change(suggestionList[0], changewith);
});

onclick event not firing in a for loop

I'm binding (or at least trying to) a function for each li element under a ul.
But the event never fires. Take a look at the code below, the alert saying "foo"
is showing, but the next one saying "bar" is supposed to show once a click
on the li tag is invoked.
function set_search_value()
{
var e = document.getElementById("res_ls");
alert("foo");
for (var i = 0; i < e.children.length; i++)
{
e.children[i].onclick = function() {
alert("bar");
}
}
}
HTML
<ul id="res_ls" class="visible">
<li><span><span class="highlighted">test</span>ing.com</span> <span>(181)</span></li>
</ul>
I dropped your exact code into a jsFiddle and it appears to function as desired: http://jsfiddle.net/qVQU4/
I have one piece of advice to offer, though: Attaching individual click handlers to each <li> element can be problematic for performance reasons in long lists, and also requires extra coding gymnastics if items in the list are being manipulated via javascript on the client side. A better technique would be to attach a single event handler to the parent container, and let the click bubble up to that level.
Here's an example using jQuery: http://jsfiddle.net/qVQU4/1/
$("#res_ls").on("click", "li", function(e) {
// e.target will be set to the <li> element that was clicked
alert("bar");
});
Using the latter technique, any new items added to the list will have their clicks handled automatically, without having to wire any additional event handlers.
Look at this example on the jsFiddle:
http://jsfiddle.net/drfisher/Ts7wZ/
var children = document.getElementById("res_ls").children;
var child;
for (var i = 0, len = children.length; i < len; i++) {
child = children[i];
if (child.nodeType == 1) {
child.onclick = function() {
alert(this.textContent);
}
}
}

Preventing javascript callback from being called on parent div

I'm working on a userscript which is supposed to be cross-browser compatible which might explain why I'm not doing things the normal way. The script displays a floating div named box which is a jQuery object. The click function looks like this:
box.click(function(event) {
set_visible(false);
});
The set_visible function just does a box.fadeOut(500);
Inside the parent div I create a menu not using jQuery but plain old javaScript using an array of functions like so (I tried rewriting this function using jQuery but had some issues getting the array functions to work):
function doGMMenu() {
if( !GM_falsifiedMenuCom.length ) { return; }
var mdiv = document.createElement('div');
for( var i = 0; GM_falsifiedMenuCom[i]; i++) {
var bing;
mdiv.appendChild(bing = document.createElement('a'));
bing.setAttribute('href','#');
bing.onclick = new Function('GM_falsifiedMenuCom['+i+'][1](arguments[0]); return false;');
bing.appendChild(document.createTextNode(GM_falsifiedMenuCom[i][0]));
if (i+1<GM_falsifiedMenuCom.length)
mdiv.appendChild(document.createTextNode('\u00A0\u00A0|\u00A0\u00A0'));
}
status.contents().append(mdiv);
}
Here's an example of the first array function which displays an options menu:
function() { DisplaySlideMenu(true); }
My problem is that when I click on the link, the options menu displays, but the parent divs box.click function is also called which hides it when I don't want to. When the anchor .onclick function is added you can see that the last entry is return false; but that doesn't prevent the .click event from propagating up to the parent div. Is there any way to prevent this from happening?
box.click(function(event) {
event.stopImmediatePropagation();
event.stopPropagation();
set_visible(false);
});

multiple functions in the document.ready function

here's my code:
$(document).ready(function () {
$('.flip1').click(function () {
$('.panel1').slideToggle("slow");
});
$('.flip2').click(function () {
$('.panel2').slideToggle("slow");
});
$('.flip3').click(function () {
$('.panel3').slideToggle("slow");
});
$('.flip4').click(function () {
$('.panel4').slideToggle("slow");
});
});
I want to make a loop with .flip as the variable (flipVar) and .panel as (panelVar)
Well if it were my page I'd make sure that those elements all shared a class so that I wouldn't need to loop. However, you could do this:
for (var i = 1; i <= 4; ++i) $('.flip' + i).click((function(i) {
return function() { $('.panel' + i).slideToggle('slow'); };
})(i));
The loop variable has to be trapped in a closure so that each "click" handler references the proper value. Again, I really wouldn't do it this way. I'd make the "flip" elements share a class, and then keep that index (the implicit reference to a corresponding "panel") in a separate class element or in a "data-" attribute. Then the handler could find the panel using that value.
edit — as a hack, you could leverage the fact that the class names of the related elements are both of the form "somethingNN", where "NN" is the numeric part. You could strip off the number and then append it to "panel":
for (var i = 1; i <= 4; ++i) $('.flip' + i).click(function() {
var panelClass = this.className.replace(/.*\bflip(\d+).*/, "panel$1");
$(panelClass).slideToggle('slow');
});
Even though you want to run the selector in a loop, I wouldn't do it like that because you're doing multiple DOM selections. You can get it done with one DOM selection:
$(document).ready(function () {
$('div[class^=flip]').each(function ( idx ) {
$(this).click(function() {
$('.panel' + (idx + 1)).slideToggle("slow");
});
});
});
This will work assuming that the flip elements occur on the page in their numerical order.
This uses the attribute starts with selector to get all <div> elements that have a class name starting with "flip". Change the tag name if it is different, or remove it if they don't all have the same tag.
It uses the index that .each() makes available to you in order to toggle the correct .panel.
$(document).ready(function () {
for (var i=1; i<=4; i++) {
(function(i) {
$('.flip'+i).click(function () {
$('.panel'+i).slideToggle("slow");
});
})(i);
}
});
try this:
$(function(){
for(var i=1;i<5;i++){
$('.flip'+i).click(function () {
$('.panel'+i).slideToggle("slow");
});
}
});
PS:- don't use this it will not work as pointed out by #patrick

Categories

Resources