javascript counter not adding 1 but adding 2 without intending to - javascript

I am trying to create counter that increase by one each time as follow:
var imnum=0;
(function changeImage(){
++imnum;
$( ".slider" ).fadeOut( 5000, function() {
// Animation complete.
$('#home-slider-im').attr("src",images[imnum]);
$('#home-slider-t').attr("src", imagesText[imnum]);
$( ".slider" ).fadeIn( 2000, function() {
// Animation complete
});
console.log(imnum);
setTimeout(changeImage,10000)
})})();
but the console log output is 1 3 7 15... not 1 2 3 4... am I doing something wrong? what is it? how to fix it?

I'm guessing you have more than one element with class="slider". The fadeOut callback will get called for each element that fades out. So if you have (say) two, the first call to changeImage will trigger the callback twice...and things will rapidly accelerate from there. :-)
Since your fadeout is 5000ms and your fadein is 2000ms and your delay between images is 10000ms, just move the setTimeout outside the fadeOut callback:
var imnum = 0;
(function changeImage() {
++imnum;
$(".slider").fadeOut(5000, function() {
// Animation complete.
$('#home-slider-im').attr("src", images[imnum]);
$('#home-slider-t').attr("src", imagesText[imnum]);
// $(this).stop();
$(".slider").fadeIn(2000, function() {
// Animation complete
});
//alert(i);
// console.log(i);
});
// *** Outside the callback
console.log(imnum);
setTimeout(changeImage, 10000)
})();
(I've also updated that to have consistent curly brace notation and indentation, which aids tremendously with readability.)
Side note: You appear to be getting the image information from an array, but always increasing the imnum variable and not checking whether it wraps around. This trick may be useful:
imnum = (imnum + 1) % images.length;
That will wrap back to 0 when it gets to the end of the array.
Side note 2: You seem to have parallel arrays (images and imagesText). I'd suggest using a singel array of objects instead:
var images = [
{text: "text for the image 1", src: "http://example.com/img/1"},
{text: "text for the image 2", src: "http://example.com/img/2"},
{text: "text for the image 3", src: "http://example.com/img/3"}
];
then
$('#home-slider-im').attr("src", images[imnum].src);
$('#home-slider-t').attr("src", images[imnum].text);

Your callback is called for every matched element. Based on your output, it looks like you have two elements with class .slider, so it's calling setTimeout() twice every time the function is called. Instead, you could just have the timeout outside of the callback and wait for a little bit longer:
var imnum=0;
(function changeImage(){
++imnum;
$( ".slider" ).fadeOut( 5000, function() {
// Animation complete.
$('#home-slider-im').attr("src",images[imnum]);
$('#home-slider-t').attr("src", imagesText[imnum]);
// $(this).stop();
$( ".slider" ).fadeIn( 2000, function() {
// Animation complete
});
//alert(i);
// console.log(i);
});
setTimeout(changeImage,15000)
console.log(imnum);
})();

Related

Function with attr() function not executing all statements when there are multiple elements on screen created dynamically by a function

The function below creates a red dot on the right end of the screen, animate() to move it left and when clicked, its src file should be changed, along with a few other things as you can see below:
function spawnEnemy()
{
$("body").prepend("<img src='red_dot.png' class='enemies' id='enemy' style='left:calc(" + thewidth/2 + "px)'/>");
$("#enemy").attr("id", "enemy"+i);
$("#enemy"+i).css({"left" : thewidth+'px', "top" : (randomInt(10,500))+'px'});
$("#enemy"+i).animate({left :'-400px'}, 20000);
$("#enemy"+i).click(function()
{
var snd = new Audio("laser.mp3");
snd.play(); //function stops here
$("#enemy"+i).stop();
$("#enemy"+i).attr("src","explosion.gif");
$("#enemy"+i).css({"transform" : "scale(0.11,0.11)"});
setTimeout(function()
{
$('#enemy'+i).hide();
}, 350);
});
i+=1;
}
This function is executed every six seconds. If, however, the element is not clicked before a new element is created, then all of the elements when clicked stop executing at the line where I have placed a comment. I checked the console, and I couldn't find anything of value, although I know that the problem isn't with the ids as they all have different ids in the console, and since I can hear the sound from snd.play() and none of the effects of the statements after snd.play() are seen, I'm sure the problem lies there. This problem is only when multiple elements are created, as they all execute fine if I click the element before six seconds, i.e, before the function is executed again. Also, thewidth is just a pre-defined global var, so it's not related.
I'm very new to jquery, so I apologize if there's something obvious I'm missing.
Edit: Okay, now all the statements aren't executing even if there is only one element on the screen. I'm quite lost.
Ok, I think I see what's happening. You need to reference enemy with $(this) inside the callback, because i is in the encapsulating scope, which means it can change and break the internal scope of that callback:
While at it, I cleaned up your jQuery code a little to simplify it.
function spawnEnemy() {
$('<img />', {
id: 'enemy' + i,
src: 'red_dot.png',
className: 'enemies',
style: 'left: ' + thewidth / 2 + 'px; top: ' + randomInt(10,500) + 'px'
})
.prependTo($('body'));
.animate({left :'-400px'}, 20000);
.click(function() {
var snd = new Audio("laser.mp3");
snd.play(); //function stops here
$(this).stop();
$(this).attr("src","explosion.gif");
$(this).css({"transform" : "scale(0.11,0.11)"});
setTimeout(function() {
$(this).hide();
}.bind(this), 350);
});
i+=1;
}

delay between animate.css animations

I'm kind of new to jQuery and I'm currently trying the following:
I'm using animate.css to animate a div. What I want to do now is to define a timing between fading in and fading out. For example:
Fade in > 3 sec delay > fade out
I'm using this function to dynamically add classes from animate.css to my object (#test).
$(document).ready(function () {
phase1('#test', 'bounceInLeft');
function phase1(element, animation) {
element = $(element);
element.addClass('animated ' + animation);
};
});
I'm trying to archive something like this:
phase1('#test', 'bounceInLeft');
3 sec delay
phase1('#test', 'bounceOutLeft');
1 sec delay
phase1('#test2', 'bounceInLeft');
.....
Any kind of help is really appreciated :) Thanks in advance!
Yes you setTimeout. Wrap your code within this section and adjust the timing with the amount of milliseconds that you want. This allows you to stagger code timings with multiple values..
This example will delay by three seconds, then one by five seconds..
setTimeout(function(){
// place your code in here
}, 3000);
setTimeout(function(){
// place your second bit of code in here
}, 5000);
Since you are using jQuery, you can use animation chains like that
(function($){
$(".move")
.animate({left:"+=200"},3000)
.delay()
.animate({left:"+=100"},3000);
})(jQuery);
See Example
Using jQuery chain events
$("#id").fadeIn(1000).delay(3000).fadeOut(1000);
This should work for you. All parameters specify time 1000=1Sec
http://jsfiddle.net/k8zq2fo6/
You can increase the chain
$("#id").fadeIn(1000).delay(3000).fadeOut(1000).delay(2000).fadeIn(1000).delay(3000).fadeOut(1000).delay(2000);
Try utilizing .queue()
$(function() {
// load `Animate.css`
$("style").load("https://raw.githubusercontent.com/"
+ "daneden/animate.css/master/animate.css");
// animation settings
var settings = [{
"bounceInLeft": 3000
}, {
"bounceOutLeft": 1000
}, {
"bounceInLeft": 3000
}];
$("#test").queue("bounce", $.map(settings, function(val, key) {
return function(next) {
var current = Object.keys(val)[0];
$(this)
// reset `className`
.attr("class", "")
// add `animated` , `current` `class`
.addClass("animated " + current);
// log `.queue("bounce")` iteration
console.log(this.className, current
, settings[key][current], $(this).queue("bounce"));
// "delay": `settings[key][current]` ,
// call `next` function in `.queue("bounce")`
setTimeout(next, settings[key][current]);
}
}))
.dequeue("bounce")
// do stuff when `.queue("bounce")` empty
.promise("bounce")
.then(function(elem) {
console.log(elem.queue("bounce"), "complete")
})
});
#test {
position: relative;
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="test">abc</div>
<style></style>

How to use fadeOut jQuery property with Javascript Text Snippet

http://api.jquery.com/fadeOut/ <- fadeOut api
I'm trying to learn Javascript and I've been playing with a snippet I found on Codepen.
I'm having trouble trying to get the random text array snippet to have the text fadeOut when it transitions away to another text object. Right now, the array cycles through and randomly selects a string from the array using the Math.Random function (5*1) and it fades in each time a new text object loads in, however I want it to fade out and I don't think I'm utilizing the .fadeOut property properly. How can I get it so that the text fadesOut, so the text does fadeIn fadeOut, instead of fadeIn, insta kill?
var textTimer;
var inTransition = false;
startTimer();
function startTimer() {
clearTimeout(textTimer);
textTimer = setTimeout(changeTitle, 3500);
}
changeTitle();
var titleNumber = Math.floor(Math.random() * 5) + 1;
function changeTitle() {
var titleArray = [
"Test1",
"Test2",
"Test3",
"Test4",
"Test5"
];
var tempTitleLength = titleArray.length - 1;
if (inTransition == false) {
inTransition = true;
titleNumber++;
if (titleNumber > tempTitleLength){
titleNumber = 0
}
$('.text').html('');
$('.text').css({opacity: '0'});
$('.text').html(titleArray[titleNumber]);
$('.text').fadeOut();
$('.text').stop().delay(0).animate({
opacity: 1
}, 1500, function() {
inTransition = false;
startTimer.()
});
}
}
Thanks! :D
The HTML is pretty straight forward
<div class="text"></div>
Multiple problems:
$('.text').html('');
$('.text').css({opacity: '0'});
$('.text').html(titleArray[titleNumber]);
You are already removing the text in html('') without fading out,
setting css opacity to 0 without any delay, setting html new text without any animation.
There is a syntax error also startTimer.() I guess is typo.
Remove first 2 lines and set new text after fade out is done.
You also need to wait for fadeOut to finish before doing fadeIn.
So, sequence: fadeOut, set new text, fadeIn.
Like this:
$('.text').fadeOut(1500, function () {
$('.text').html(titleArray[titleNumber]);
$('.text').fadeIn(1500, function () {
inTransition = false;
startTimer()
});
});
JSFiddle: http://jsfiddle.net/Dzyzw/
You have syntax errors in your code: you have startTimer.() should be startTimer() and you did not close your startTimer function with a }. I corrected this for you and set up a sample JSFiddle for you review. Seems to be working otherwise.
Here is the sample JSFiddle: CLICK HERE
Here's what I think you're going for--
Set initial text.
Fade out your text.
Change the text.
Fade in the new text.
Wait a while, then return to step 2.
I would drop all the transition flags and use the optional callback functions that are fired when fadeOut and fadeIn complete to move from step to step, e.g.
$('.text').fadeOut(1000, function() {
$('.text').html(get_next_word());
$('.text').fadeIn(500);
});
Just fire that off on a timer that is 1500 milliseconds + the time you want the text to be fully visible.

jQuery animate within animate callback works only once

I have two pagination links which trigger a jQuery animation.
A callback function on the animation triggers a second animation.
This works fine, however, it only works the first time the function is called.
Each time after, the first of the 2 animations works and the second one does not, it merely changes the CSS without the effect.
I'm racking my brain here, to no effect (pun intended).
function switchItem(e) {
e.preventDefault();
// If not current piece
if($(this).hasClass('light')) {
/* VARIABLES */
var container = $('.portfolio footer .portfolio_content');
var link = $(this).attr('id');
var newItem = $(this).html();
/*===================================================
* This is the Key part here
===================================================*/
/* FIRST ANIMATION */
container.animate({
'right':'-100%'
}, 300, 'swing',
// Callback Function
function() {
$(this).html('').css({'left':'-100%'});
$.get('inc/portfolio/'+link+'.php', function(data) {
container.html(data);
/* SECOND ANIMATION */
container.animate({
'left':'0%'
}, 300, 'swing');
});
});
}
}
Here is the demonstration: http://eoghanoloughlin.com/my_site/#portfolio
See working sample here, your left is conflicting with your first right -100% animation and at the end if you don't reset the right then it will conflict with your second left animation
http://jsfiddle.net/PAdr3/2/
reset left before animating
container.css('left', 'auto');
and reset right when complete
container.animate({
'left':'0%'
}, 300, 'swing', function() {
$(this).css('right', 'auto');
});
When you replace the html in a page with new content, it will not automatically add listeners or other jquery enhancements that are added via javascript.
I suspect you need to apply these again after you put the content you fetched with $.get into the page.
Another alternative, is to add all the content in one load, but make the second page hidden. This is probably a nicer alternative than using $.get
I think that the animate function does not string until the first animate is ready. The docs say:
If supplied, the complete callback function is fired once the
animation is complete. This can be useful for stringing different
animations together in sequence.
Something like this might work:
function switchItem(e) {
e.preventDefault();
// If not current piece
if($(this).hasClass('light')) {
/* VARIABLES */
var container = $('.portfolio footer .portfolio_content');
var link = $(this).attr('id');
var newItem = $(this).html();
/*===================================================
* This is the Key part here
===================================================*/
/* FIRST ANIMATION */
container.animate({
'right':'-100%'
}, 300, 'swing',
// Callback Function
function() {
$(this).html('').css({'left':'-100%'});
$.get('inc/portfolio/'+link+'.php', function(data) {
container.html(data);
});
}).complete(
/* SECOND ANIMATION */
container.animate({
'left':'0%'
}, 300, 'swing');
);
}
}

Is there any way to make two jQuery animations run (properly) simultaneously?

I have an event listener that calls two animation actions. Unfortunately their starts are staggered by a small amount (e.g. the first in the function starts first).
Does anyone know a way to properly sync them up?
Here's my code:
$("#nav ul li a").hover(
function(){
$(lastBlock).children("div").animate({width: "0px"}, { queue:false, duration:400, easing:"swing" });
$(this).children("div").animate({width: maxWidth+"px"}, { queue:false, duration:400, easing:"swing"});
lastBlock = this;
}
);
Because the first animation runs slightly before the second, it causes the overall width to become momentarily unequal, which looks a bit funky.
There was a recent disussion about this exact topic on the jQuery dev list. They created a few test cases you might wanna look at. Specially the Johns test.
Here's the discussion topic btw.
The trick is to have a single interval/callback in which all elements are updated.
You can find an example in my post here:
Can I implement a callback with each animation step in jQuery?
What you end up is basically:
var el1 = $("#element1");
var el2 = $("#element2");
var animation = new AnimationTimeline( {
easing: "swing"
, onstep: function( stepValue, animprops )
{
// This is called for every animation frame. Set the elements:
el1.css( { left: ..., top: ... } );
el2.css( { left: ..., top: ... } );
}
});
// And start it.
animation.start();

Categories

Resources