I am totally stumped here.
I have a bunch of messages, each within a div "msg_feed_frame_$i" which increases, so message 1 is in div "msg_feed_frame_1", msg 2 is in "msg_feed_frame_2", etc etc. I want to fade these messages in one by one using jquery, but for some reason no matter what I do with settimeout and setinterval, the code immediately fades them all in simultaneously.
This is what i've got so far:
function feed(i)
{
var div = "#msg_feed_frame_";
var fader = div.concat(i);
$(fader).fadeIn(2000);
}
function timefade()
{
var num = 1;
for (num=1; num<=10; num++)
{
var t=setTimeout(feed(num),1000);
}
}
$(document).ready(function(){
timefade();
});
Your problem is that the for loop executes quickly and sets a timeout 1000ms from now for each function call. Here's one way you could remedy this:
function feed(i) {
var div = "#msg_feed_frame_";
var fader = div.concat(i);
$(fader).fadeIn(2000);
}
function timefade() {
var num = 1;
var fadeIt = function(i) {
return function() { feed(i); };
};
for (num = 1; num <= 4; num++) {
var t = setTimeout(fadeIt(num), num * 1000);
}
}
$(document).ready(function() {
timefade();
});
Additionally, your original code was passing setTimeout the results of the feed(i) function call (undefined), and it expects an object of type function. I added a helper function that returns a reference to a function that will call feed with the correct argument.
Capturing the value of num inside a function is called a closure, and it can be confusing at first. Check this post out for some good explanations of closures inside loops and while they're necessary.
Here's your example, working: http://jsfiddle.net/andrewwhitaker/tpGXt/
Try using jQuery's .delay() function...
function feed(i){
var div = "#msg_feed_frame_";
var fader = div.concat(i);
$(fader).fadeIn(2000).delay(1000);
}
function timefade(){
var num = 1;
for (num=1; num<=10; num++){
feed(num);
}
}
$(document).ready(function(){
timefade();
});
Related
I am trying to write a javascript program which stores the value from an input element in an array when a button is clicked. The array is the split and each individual letter added to a span element and then appended to the document. The idea is to create a typing effect using setTimeout.
I am running into an issue creating a closure within the loop, so currently the setTimeout function always returns the final value of the iteration.
The function in question is at the bottom of the code block and called addTextToBoard();
var noteButton = document.querySelector('[data-js="button"]');
noteButton.addEventListener("click",function() {
var messageIn = document.querySelector('[data-js="input"]');
var message = messageIn.value;
postToBoard(message);
});
function postToBoard(val) {
var noteBoard = document.querySelector('[data-js="noteboard"]');
var newElement = document.createElement('div');
newElement.classList.add('noteboard__item');
noteBoard.appendChild(newElement);
setTimeout(function(){
newElement.classList.add('active');
}, 200);
addTextToBoard(newElement, val);
}
function addTextToBoard(el, val) {
var wordArray = val.split('');
for(i = 0; i < wordArray.length; i++) {
var letter = document.createElement('span');
letter.innerHTML = wordArray[i];
setTimeout(function(x){
return function() {}
el.appendChild(letter);
}(i),1000);
}
}
I believe I am close, I'm just not fully understanding the syntax for creating the closure. If someone could give poke in the right direction, without necessarily giving the full solution that would be great.
I essentially tried to paste in the following code snippet from here but I've missed something somehwere along the way!
setTimeout(function(x) { return function() { console.log(x); }; }(i), 1000*i);
Best,
Jack
You are close.
Since the "letter" variable changes, you'll add only the last letter over and over again. You need to "save" the current letter on the setTimeout() callback function, One way to go is like this:
function appendMyLetter(letter) {
return(function() {
el.append.Child(letter);
});
}
function addTextToBoard(el, val) {
var wordArray = val.split('');
for(i = 0; i < wordArray.length; i++) {
var letter = document.createElement('span');
letter.innerHTML = wordArray[i];
setTimeout(appendMyLetter(letter), 1000);
}
}
This way, the appendMyLetter() function gets called with a different parameter (one for each letter) and returns a function with the correct "stored" value to be called by setTimeout().
EDIT
Looking at your setTimeout() code closely
setTimeout(function(x){
return function() {}
el.appendChild(letter);
}(i),1000);
It would work fine, if you used the proper parameters and used the appendChild() inside the returned function, like so:
setTimeout(function(x){
return(function() {
el.appendChild(x);
});
}(letter),1000);
You can create an immediately-invoked function expression IIFE to create a closure
function addTextToBoard(el, val) {
var wordArray = val.split('');
for(i = 0; i < wordArray.length; i++) {
(function(index) {
var letter = document.createElement('span');
letter.innerHTML = wordArray[i];
setTimeout(function(){
el.appendChild(letter);
},1000);
})(i);
}
}
I dont know if this will work but here you go a slight change in operator:
letter.innerHTML += wordArray[i];
if you dont get the effect you imagined you will get you better try to increment the timer by i like this
setTimeout(function(){
...
},1000*i);
I created a function that would do something unique on it's 3rd call. In this case, alert the incremented number. However, when trying to call this function from another function:
"MyFunction();", I get Uncaught TypeError: Object [object global] has no method 'MyFunction'. Can you please tell me what I'm doing wrong?
var counter = 0;
var num = 0;
function = MyFunction() {
// increment outside counter
counter++;
if (counter === 3) {
// do something every third time
num++;
alert('the new number is: ' + num);
// reset counter
counter = 0;
}
}
I've also tried removing the = sign, as you can see here http://jsfiddle.net/DN3yC/6/ it doesn't work.
LIVE DEMO
Just remove the = sign function MyFunction() { and make sure in your fiddle that JS <script> is in the right placeSee additional explanation below.
Example:
var element = document.getElementById('button');
var counter = 0;
var num = 0;
function MyFunction() {
counter = ++counter % 3; // loop count
if ( !counter ) {
num++;
alert('the new number is: ' + num);
}
}
//On click:
element.addEventListener('click', MyFunction, false);
your new fiddle: http://jsfiddle.net/DN3yC/7
The old one of yours was not working cause you did not used No Wrap - in body for the JS in your fiddle. (See options panel at the left up corner)
So basically you need to put your <script> tags before your </body> closing tag in order to make sure the DOM is ready and parsed by JavaScript before elements manipulation.
Syntacs looks wrong to me, try
var foo = Myfuntion();
or
var foo = new MyFuntion();
depending on what MyFuntion() is.
It should be:
var MyFunction=function () {
// increment outside counter
counter++;
if (counter === 3) {
// do something every third time
num++;
alert('the new number is: ' + num);
// reset counter
counter = 0;
}
}
My code is supposed to make a set of divs with classes that start with status- fade out then change the classes from ie status-1 to status-11 by adding 10 the number. Everything is working except that the parseint is looping and the classes are becoming status-179831, status-179832...
$(function disappear(){
$('[class^="status-"]').delay(5000).fadeOut(400)
$('[class^="status-"]').each(function(){
num = $(this).attr('class').split('status-')[1];
num = parseInt(num, 10) + 10;
$(this).attr("class", "status-"+num+"");
})
$('[class^="status-"]').delay(1000).fadeIn(400)
disappear();
})
To get your operations to work in sequential order, you need to use the completion function of your animations like this:
$(function (){
function runOne(item) {
item.delay(5000).fadeOut(400, function() {
var num = item.attr('class').split('status-')[1];
num = parseInt(num, 10) + 10;
item.attr("class", "status-"+num+"")
.delay(1000).fadeIn(400, function() {runOne(item)});
});
}
// start all the animations
$('[class^="status-"]').each(function() {
runOne($(this));
});
})
Working demo: http://jsfiddle.net/jfriend00/k7aS7/
As your code was written, the two animations are asynchronous and your .each() loop or the next call to disappear() do not wait for the animations to finish. Using the completion functions like this triggers the next part of your sequence when the animation is done. You also want to always make sure you're using var in front of local variables to avoid accidentally making them global variables.
You can also synchronize a promise object which will guarantee that all the animations always start at the same time on each iteration:
$(function disappear() {
var all = $('[class^="status-"]');
all.delay(5000).fadeOut(400, function() {
var item = $(this);
var num = item.attr('class').split('status-')[1];
num = parseInt(num, 10) + 10;
item.attr("class", "status-"+num+"")
item.delay(1000).fadeIn(400);
})
// when all animations are done, start the whole process over again
all.promise().done(disappear);
})
Working demo of this option: http://jsfiddle.net/jfriend00/SY5wr/
To restore the class names to the original class name after each iteration, you could do this:
$(function () {
// save original class names
var all = $('[class^="status-"]').each(function() {
$(this).data("origClassName", this.className);
});
function disappear() {
all.delay(5000).fadeOut(400, function() {
var item = $(this);
var num = item.attr('class').split('status-')[1];
num = parseInt(num, 10) + 10;
item.attr("class", "status-"+num+"")
item.delay(1000).fadeIn(400);
})
// when all animations are done, start the whole process over again
all.promise().done(function() {
// restore class names
all.each(function() {
this.className = $(this).data("origClassName");
})
// run it all again
disappear();
});
}
// start it
disappear();
})
Working demo: http://jsfiddle.net/jfriend00/hTmHL/
I'm trying to figure out how this custom jQuery functions work by experimenting a bit. I can't however get it to work properly. I'm trying to call the prepareSlide function in my setInterval but it says prepareSlide is not defined
$('document').ready(function(){
jQuery('.item_holder').itemSlider({
start: 1,
carousel: true
});
});
$.fn.itemSlider = function (details) {
var currentSlideNumber = (details && details.start > 0) ? details.start : 1;
this.prepareSlide = function(slideNumber) {
alert(1)
}
//Set an interval
var itemToSlide = currentSlideNumber + 1;
slideTimer = setInterval("prepareSlide(" + itemToSlide + ")", 5000);
}
You should provide a function to the first argument of setInterval. Also, to provide the context properly to the function invocation, a quick method is to preserve this by having another variable reference it, which in this case, we call self
var self = this;
slideTimer = setInterval(function(){
self.prepareSlide(itemToSlide)
}, 5000);
My code looks something like:
$(document).ready(function(){
var cont = 0;
function func1(cont)
{
//Some code here
search.setSearchCompleteCallback(this, searchComplete, null);
//Some other code
}
func1(cont);
function searchComplete()
{
//Some code
cont += 1;
if (cont < length ) {
func1(cont);
} else {
// Other code
}
}
});
So what I want to do is delay the execution of func1(cont); inside of the searchComplete() function. The reason for this is that all the code does is to work with the Google search API and PageRank checks and I need to slow down the script so that I won't get banned. (Especially for the requests it makes regarding the PR check).
If I simply use setTimeout() on func1(cont); it says there is no func1() defined, if I try to get the function outside $(document).ready() it sees the function but the Google code won't for for it needs the page completely loaded.
How can I fix setTimeout or how can I pause the script for a number of seconds ?
Thanks!
Write
func1(cont);
as
window.setTimeout(function() {
func1(cont);
}, 1000);
Instead of declaring the function like this:
function func1(cont) {}
declare it like this:
var func1 = function(cont) {}
You'll need to rearrange your code a little:
$(document).ready(function(){
var cont = 0;
var func1;
var searchComplete = function()
{
//Some code
cont += 1;
if (cont < length ) {
func1(cont);
} else {
// Other code
}
}
func1 = function(cont)
{
//Some code here
search.setSearchCompleteCallback(this, searchComplete, null);
//Some other code
}
func1(cont);
});
I'd try something like this. I prefer to declare the vars and functions inside the jquery namespace, but you could equally move the cont variable and the functions outside of the document ready function and have them available globally.
$(document).ready(function(){
$.cont = 0;
$.func1 = function() {
//Some code here
search.setSearchCompleteCallback(this, $.searchComplete, null);
//Some other code
}
$.searchComplete = function() {
//Some code
$.cont += 1;
if (cont < length ) {
setTimeout($.func1,1000);
} else {
// Other code
}
}
setTimeout($.func1,1000); // delay the initial start by 1 second
});
Hopefully I've got your description correct:
document.ready() event fires
Inside document.ready() you want a function to be called after X milliseconds
This function wires up the Google object search.setSearchCompleteCallback() to another function (which it looks like it needs a parent object from the this)
If this is the case, why do you need any of the functions declared inside the document.ready() scope? Can you't simply make all 3 global? e.g.
var search = null; // initialise the google object
var cont = 0;
function timedSearch()
{
search.setSearchCompleteCallback(this, searchComplete, null);
}
function searchComplete()
{
if (++cont < length) // postfix it below if this is wrong
setTimeout(timedSearch,1000);
}
$(document).ready(function()
{
setTimeout(timedSearch,1000);
}
Hit me with the downvotes if I've misunderstood.