first time my function runs fine, second time its wrong jquery - javascript

I'm trying to make a lightbox. But when i open the lightbox for the second time. It goes trough my code twice. When i open my lightbox the third time, it goes trough my code three times. Don't get it at all.
$(document).ready(function(){
$('.bg-overlay, .overlay-content, .overlay-content img').hide();
$('.thump-bnr > li').click(function(){
// show the overlay and bg-overlay
$('.bg-overlay, .overlay-content').fadeIn(500);
// gets the index of the thunp thats been clicked in the banner
var x = $(this).index();
// console.log(x);
$('.overlay-content > img').eq(x).fadeIn(500);
// thumpPop checks if there aren't to mutch list items
var thumpPop = $('.overlay-content .thump-pop li').length;
// console.log(thumpPop);
// appends all li for the thump navigation in the overlay
if (thumpPop < 1) {
$('.overlay-content').append('<ul class="thump-pop"></ul>');
for (var i = 0; i < 4; i++) {
$('.thump-pop').append('<li></li>');
}
}
// sets all thump li to the border white
$('.thump-pop > li').css("border-color", "#fff");
// sets the active thump li to a dark border
$('.thump-pop > li').eq(x).css("border-color", "#e2e2e2");
// console.log(x);
// calls the thumpNav function for the thump navigation
thumpNav();
// calles the arrowNav function for the arrow navigation beside the big images
arrowNav();
});
In this function i have managed to execute the function only once by using an if statement.
// this is the function for the thump navigation
function thumpNav() {
$('.thump-pop > li').click(function(){
// get the index number of the thump li
var y = $(this).index();
// console.log(y);
// checks if the big image thats equal to the clicked thump is hidden
if($('.overlay-content > img').eq(y).is(':hidden')) {
// fadeIn and fadeOut the big images
$('.overlay-content img').fadeOut();
$('.overlay-content > img').eq(y).fadeIn();
// this wil change the border color of the active li
$('.thump-pop > li').css("border-color", "#fff");
$(this).css("border-color", "#e2e2e2");
}
});
}
I think i have made a mistake in the function arrowNav(), because he executes this twice when i open my lightbox for the second time.
function arrowNav() {
$('.arrow-nav-left').click(function(){
// this wil get the index number of the visible image in the overlay. This number can be used to display the number -1 our +1
var x = $('.overlay-content').find('img:visible').index();
// console.log(x);
var x = x - 2;
console.log(x);
$('.overlay-content > img').hide();
$('.overlay-content > img').eq(x).show();
});
}
// hides the pop-up
$('.bg-overlay').click(function(){
$('.bg-overlay, .overlay-content, .overlay-content img').fadeOut(500);
});
});
Please help me, and some feedback on the code is alway helpfull. Thanks

The problem is here:
function thumpNav() {
$('.thump-pop > li').click(function(){
You're attaching a new click handler everytime you call thumpNav, and they will all execute and do the same thing everytime you click.
Replace with:
function thumpNav() {
$('.thump-pop > li').unbind("click").click(function(){
Just like you did with arrowNav().
Note that your code is very unefficient and not structured quite right. Even if this works it's not good when you're juggling click handlers like this. At least define the callback as a seperate function and pass that as an argument to click().
If you want to get help with improving your code, you can always post it on Codereview.

Every time you're calling:
thumpNav();
you're attaching a new click handler.
same with arrowNav()
but atleast here you unbind first.

Related

Switching between divs like pages

I have several div elements with incremental IDs (e.g. div0, div1, div2 (I know this is bad practice - I'm developing a dynamic CSV-to-HTML converter for Outlook calendar exports)) and I'd like to switch between them using jQuery linked to forward/back buttons . What I'm trying to do is as follows (in meaningless pseudo-code):
int pos = 0
forward.onclick
hide ("#div"+pos)
pos++
show ("#div"+pos)
back.onclick
if pos != 0
hide ("#div"+pos)
pos--
show ("#div"+pos)
Since I know next to nothing about jQuery, my questions are 1. What would the syntax be for implementing the above example (assuming I'm on the right track), and 2. Is there a way in jQuery to somehow check for an upper boundary so the counter doesn't increase above the number of divs?
If you want to know how many divs you have in jQuery, select them and take the length of your selection:
$('.div').length
You could even just use that selection to cycle through which divs to show:
var $divs = $('.div');
var upperLimit = $divs.length - 1;
var index = 0;
// on arrow click
$($divs[index]).hide();
index++ (or index--, depending on the arrow)
$($divs[index]).show();
int is not a data type in JavaScript. Use var. Declaration would be var pos = Number(0). To prevent exceeding the boundaries of number of divs, declare a variable with the number of divs you have, and inside your hide and show calls, use posâ„…divLength instead of pos. Suppose you have total divs as 4, you will never exceed div3 this way. It will iterate from div0 to div3. Refer this to learn how to use show and hide methods.
Here's a demo.
var index = 0;
$('#div' + index).show();
$('#next').click(function () {
index++;
$('#back').prop('disabled', false);
if (index === fakeData.length - 1) {
$('#next').prop('disabled', true);
}
$('.items').hide();
$('#div' + index).show();
});
$('#back').click(function () {
index--;
$('#next').prop('disabled', false);
if (index === 0) {
$('#back').prop('disabled', true);
}
$('.items').hide();
$('#div' + index).show();
});
The above code will disable and enable the next and back buttons based on whether you are at the beginning or the end of your list of data. It hides all elements and then shows the specific one that should be shown.

jQuery making a loop of functions, each with an animate queue

So this is a bit of a head scratcher and I've resorted to asking for help with it. I have created a series of functions with jQuery. Each function contains an animate() queue and ends with a call back that loads the next function, again with it's own animate() queue. Once it reaches the end it calls the first function again and around we go. I have separated the queues into independent functions, because I want to be able to jump to specific points in the loop based on user clicks. So in the code below the loop runs through once, but when it goes back to the beginning the show() and hide() bits don't appear to be doing anything. Any help with this is greatly appreciated!
var firstItem = jQuery('#vehicle-banner-one');
var firstThumb = jQuery('#thumb-one');
var secondItem = jQuery('#vehicle-banner-two');
var secondThumb = jQuery('#thumb-two');
var thirdItem = jQuery('#vehicle-banner-three');
var thirdThumb = jQuery('#thumb-three');
var nextItem = firstItem;
var nextThumb = firstThumb;
firstItem.hide();
secondItem.hide();
thirdItem.hide();
function leadIn(){
console.log('leadIn');
thirdItem.css({zIndex:8});
secondItem.css({zIndex:9});
firstItem.css({zIndex:10});
firstItem.fadeIn("slow", function(){ holdOne(); });
}
function holdOne(){
console.log('holdOne');
thirdItem.css({zIndex:8}).hide();
secondItem.css({zIndex:9}).hide();
firstItem.css({zIndex:10}).show();
firstItem.delay(3000).delay(0, function(){ transTwo(); });
};
function transTwo(){
console.log('transTwo');
thirdItem.css({zIndex:8}).hide();
secondItem.css({zIndex:10}).hide();
firstItem.css({zIndex:9}).show();
secondItem.fadeIn("slow" , function(){ holdTwo(); });
};
function holdTwo(){
console.log('holdTwo');
thirdItem.css({zIndex:8}).hide();
secondItem.css({zIndex:10}).show();
firstItem.css({zIndex:9}).hide();
secondItem.delay(3000).delay(0, function(){ transThree(); });
};
function transThree(){
console.log('transThree');
thirdItem.css({zIndex:10}).hide();
secondItem.css({zIndex:9}).show();
firstItem.css({zIndex:8}).hide();
thirdItem.fadeIn("slow" , function(){ holdThree(); });
};
function holdThree(){
console.log('holdThree');
thirdItem.css({zIndex:10}).show();
secondItem.css({zIndex:9}).hide();
firstItem.css({zIndex:8}).hide();
thirdItem.delay(3000).delay(0, function(){ transOne(); });
};
function transOne(){
console.log('transOne');
thirdItem.css({zIndex:9}).show();
secondItem.css({zIndex:8}).hide();
firstItem.css({zIndex:10}).hide();
firstItem.fadeIn("slow" , function(){ holdOne(); });
};
leadIn();
///toggle by clicking thumbnails
jQuery('#thumb-one').on('click', function(){console.log('1'); holdOne();});
jQuery('#thumb-two').on('click', function(){console.log('2'); holdTwo();});
jQuery('#thumb-three').on('click', function(){console.log('3'); holdThree();});
});
looks kinda complicated... all i understood was, that you are looking for a way to loop through a list of items AND interrupt the loop any time with a click and then start from there on...
i've needed something similar some time before... we start with the snippet from css-tricks.com
All he does, is using the setInterval function to cycle through the elements:
$("#slideshow > div:gt(0)").hide();
setInterval(function() {
$('#slideshow > div:first')
.fadeOut(1000)
.next()
.fadeIn(1000)
.end()
.appendTo('#slideshow');
}, 3000);
this is neat and nice. it shows the first element, fades it out, takes the next element, fades it in and finally appends the first element to the end of the list.
this means, that the visible element is always the first one and therefore good to address.
that was it from css-tricks ... now we are out on our own, and we do want to have a link list, to directly address the single slides... i choose to enumerate all my pages, so this was my solution:
for (i = 1; i <= $("#slides div").length; i++) {
var slideName = $("#slides div").eq(i - 1).attr("name");
$("#slideselect").append("<a href='#' class='singleSelect' name='" + slideName + "'>" + i + " </a>");
}
having a link-list, won't help, as long as you don't have a click function. since the links are inserted after document.ready, i had to use on("click", , function), to have the click handle available...
the function first of all finds the name of the clicked element and compares it to the current active element. in case they match, we won't do anything, since the clicked slide is already shown.
$("#slideselect").on("click", ".singleSelect", function () {
var clickedSlide = $(this).attr("name");
var activeSlide = $('#slides > .activeSlide').attr("name");
clearInterval(cycleHandle);
if (clickedSlide != activeSlide) {
then, because we don't want to destroy our ordered list, we loop through our elements always moving the first one to the last position, until we found our clicked element. afterwards, we fadeout the active slide and fade in the clicked one...
while (clickedSlide != $('#slides > div:first').attr("name")) {
$('#slides > div:first').appendTo('#slides');
}
$('#slides > .activeSlide').fadeOut(1000)
.removeClass("activeSlide").end();
$('#slides > div:first').fadeIn(1000)
.addClass("activeSlide")
.end();
}
cycleHandle = setInterval(function(){myCycle()}, 3000);
});
the code inside my post is already the finished version. what you may notice is the clearInterval and setInterval call... if you won't clear the interval, the clicked slide will correct fade in to display, but the interval keeps running with the old offset. e.g. if you click a page 1 sec before the interval-loop would move on, your clicked slide will be there for only 1sec...
so i took the css-trick snippet into my own cycle function, and call this once after document ready. and inside the click handle, you'll stop the interval and start it again...
well hope you understood my work... here's the fiddle: http://jsfiddle.net/sx1mozeg/2/
there is still strange behaviour with the transitions, if you spam your clicks... need to improve that ...

Fade a function out from another function

I have a function that is fading in and out of four boxes that are in a row and then it loops through again and again. Box 1 fades in and out, then box 2, then box 3, and finally box 4. This is done in one function.
I have another function that when a user hovers over the heading of one of these boxes that box will fade in. Then when they hover off it fades out. What I want to do in that function is when they hover on one of the headings over the box, the function controlling the looping (startSlider) will fade out, then when they hover off the heading the looping begins again.
Here is some code:
function startSlider(){
//code that is looping through each box is here
};
function hoverHere(){
$('.headings .b1').on("mouseenter", function(){
$('.box #1').fadeIn(300);
//startslider() fade out this function
})
.on("mouseleave", function(){
$('.box #1').fadeOut(300);
//startslider() begins again
});
//there is the same code here for .b2 and .box #2 and so on
}
Thanks for any help on how to stop this function from looping when hover is in effect and then to start the startSlider() function when hover is off.
I've put everything in one function so all the variables will be
in scope.. also I'm using .index() which gives you the index of the element
in regards to its parent (a simpler way of connecting between the boxes clicked and the infoboxes affected.
To make the loop start right away, I've separated the actual sliding function from the looping interval, so you can call the function separately in the beginning and then start the loop.. Notice you only need to call startSlider() function in doc ready. Let me know if you have any issues.. If you rather do it the other way and only want the loop function to start immediately than you can just separate the sliding function as in the example.
function startSlider(){
// timer
var loop = 0;
// get total boxes
var count=$('.box .info').length;
// slide index
var sliderIndex = 0;
// boxes
var boxes = $(".headings").children("div");
// info boxes
var infoboxes = $("#main_cont").find(".info");
// bind boxes hover
boxes.off().on('mouseenter', handlehover);
function resetSlider() {
window.clearInterval(loop);
loop=window.setInterval(moveSlider, 2000);
}
function moveSlider() {
if(sliderIndex+1 == count){ //will reset to first image when last image fades out
sliderIndex = 0;
}
infoboxes.fadeOut(400);
infoboxes.eq(sliderIndex).fadeIn(400); // slider image + the next image in the slider
sliderIndex++;
}
function handlehover() {
var boxnum = $(this).index();
boxes.off().on('mouseleave', resetSlider);
pauseSlider();
}
function pauseSlider() {
window.clearInterval(loop);
infoboxes.not(":eq("+boxnum+")").fadeOut(400);
infoboxes.eq(boxnum).fadeIn(400);
}
}
$(function() {
startSlider();
});

How to reduce 180 lines of code down to 20 in Javascript?

I have a lot of click handler functions which are almost (textually and functionally) identical. I've got a menu with maybe 10 items in it; when I click on an item, the click handler simply makes one div visible, and the other 9 div's hidden. Maintaining this is difficult, and I just know there's got to be a smart and/or incomprehensible way to reduce code bloat here. Any ideas how? jQuery is Ok. The code at the moment is:
// repeat this function 10 times, once for each menu item
$(function() {
$('#menuItem0').click(function(e) {
// set 9 divs hidden, 1 visble
setItem1DivVisible(false);
// ...repeat for 2 through 9, and then
setItem0DivVisible(true);
});
});
// repeat this function 10 times, once for each div
function setItem0DivVisible(on) {
var ele = document.getElementById("Item0Div");
ele.style.display = on? "block" : "none";
}
Create 10 div with a class for marking
<div id="id1" class="Testing">....</div>
<div id="id2" class="Testing">....</div>
<div id="id3" class="Testing">....</div>
and apply the code
$('.Testing').each(function() {
$(this).click(function() {
$('.Testing').css('display', 'none');
$(this).css('display', 'block');
}
}
$(document).ready(function (){
$("div").click(function(){
// I am using background-color here, because if I use display:none; I won't
// be able to show the effect; they will all disappear
$(this).css("background-color","red");
$(this).siblings().css("background-color", "none");
});
});
Use .siblings() and it makes everything easy. Use it for your menu items with appropriate IDs. This works without any for loops or extra classes/markup in your code. And will work even if you add more divs.
Demo
Fiddle - http://jsfiddle.net/9XSJW/1/
It's hard to know without an example of the html. Assuming that there is no way to traverse from the menuItem to ItemDiv - you could use .index and .eq to match up the elements based on the order they match with the selector.
var $menuItems = $("#menuItem0, #menuItem1, #menuItem2, ...");
var $divs = $("#Item0Div, #Item1Div, #Item2Div, ...");
$menuItems.click(function(){
var idx = $(this).index();
// hide all the divs
$divs.hide()
// show the one matching the index
.eq(idx).show();
})
Try
function addClick(i) {
$('#menuItem'+i).click(function(e) {
// set nine divs hidden, 1 visble
for( var j = 0; j < 10; ++j ) {
var ele = document.getElementById("Item"+j+"Div");
ele.style.display = (i == j ? "block" : "none");
}
});
}
// One click function for all menuItem/n/ elements
$('[id^="menuItem"]').on('click', function() {
var id = this.id; // Get the ID of the clicked element
$('[id^="Item"][id$="Div"]').hide(); // Hide all Item/n/Div elements
$('#Item' + id + 'Div').show(); // Show Item/n/Div related to clicked element
});
Obviously this would be much more logical if you were using classes instead:
<elem class="menuItem" data-rel="ItemDiv-1">...</elem>
...
<elem class="ItemDiv" id="ItemDiv-1">...</elem>
$('.menuItem').on('click', function() {
var rel = $(this).data('rel'); // Get related ItemDiv ID
$('.ItemDiv').hide(); // Hide all ItemDiv elements
$('#' + rel).show(); // Show ItemDiv related to clicked element
});
Save the relevant Id's in an array - ["Item0Div", "Item1Div", ...]
Create a generic setItemDivVisible method:
function setItemDivVisible(visible, id) {
var ele = document.getElementById(id);
ele.style.display = visible ? "block" : "none";
}
And set your click handler method to be:
function(e) {
var arrayLength = myStringArray.length;
for (var i = 0; i < idsArray.length; i++) {
setItemDivVisible(idsArray[i] === this.id, idsArray[i]);
}
}
I think this will do the trick

making function with multiple variables to pass javascript/jquery

I have a little snippet I want to make into a function. But I'm new to javascript. Obviously there is something wrong with the way I pass variables or the way I call them...
So in nutshell, this works: http://jsfiddle.net/kkvbz/
But this doesn't: http://jsfiddle.net/PrtD4/
Problem is I need it as a function, so I've to make 1 version work.
Full snippet:
function cutandMakeslides (containerid,liperslide) {
//This is for footer slider, it rewrites 1 ul into several uls that contain 4 li max.
// get the container, useful for later too...
var container = $(containerid);
// get all available UL and LI elements...
var li_elements = container.find("> UL > LI").clone();
// remove the current content so that we can rebuild it for the slider...
container.find("> UL").remove();
// build the slider container...
var slide_container = $("<div />");
// tricky part: looping through the LI's and building each of the slides...
// first create some helpful variables...
var li_elements_per_slide = liperslide;
var li_counter = 0;
// create the first slide, with a UL to hold the LI's...
var current_li_div = $("<div />");
current_li_div.append($("<ul />"));
// loop through the LI's...
li_elements.each(function(index, element){
li_counter++;
var current_li = $(element).clone();
current_li_div.find("> UL").append(current_li);
if (li_counter % li_elements_per_slide == 0)
{
// we've hit 4 in this list, so add the slide and make
// a new one, using same code as before...
container.append(current_li_div);
current_li_div = $("<div />");
current_li_div.append($("<ul />"));
}
});
// we might have an uneven number of LI's, so we need to check for this...
if (li_counter % li_elements_per_slide != 0)
container.append(current_li_div);
} // end function cutandMakeslides
//activate function above
$(function() { cutandMakeslides(".fproductslides",3); });
Problematic parts:
function cutandMakeslides (containerid,liperslide) {
var container = $(containerid);
var li_elements_per_slide = liperslide;
}
$(function() { cutandMakeslides(".fproductslides",3); });
So after extensive testing and moving the code to a fiddle, the problem seems to have resolved itself during moving it to the fiddle, so we believe there was a minor spelling or syntax error...however using a code comparison tool I was unable to find anything...
none of the problematic parts seemed to have an error:
function cutandMakeslides (containerid,liperslide) {
var container = $(containerid);
var li_elements_per_slide = liperslide;
}
$(function() { cutandMakeslides(".fproductslides",3); });
Here's a copy of the working fiddle
From your 'problematic parts' section it appears you are trying to pass a class(".fproductslides" is a class, classes start with '.' and Id's start with '#') instead of an Id as your variable names lead me to believe you want to do...

Categories

Resources