javascript/jquery loop execute function after every iteration - javascript

var dagaData = ['Manok', 'Pusa', 'Daga', 'Ibon', 'Aso'];
$('#clicktest').on('click', function() {
$.each(dagaData, function(index, item) {
executeData(item);
alert(item);
});
});
function executeData(item) {
var items = $("<div></div>").text(item);
$('#pangtest').append(items);
}
Is it possible to execute the function on every iteration?
Right now when I run the code above it finished all iteration before the append happen.
That why I've put alert to see if every alert append each iteration.
Output of code above: alert('Manok'), alert('Pusa') ,alert('Daga'), alert('Ibon'), alert('Aso') executed append.
What I'm trying to achieve is alert('manok') append, alert('Pusa') append, alert('Daga') append, alert('Ibon') append, alert('Aso') append.
Thanks in advance.

In a general sense, although the DOM is updated each time you call .append() the browser won't actually repaint the screen until after the entire JS function finishes. (Though some browsers will repaint at the point when an alert is open, which is why using alert() for debugging is a bad idea: it can subtly change the behaviour in a way that calling console.log() doesn't.)
You can work around this by using a setTimeout-based pseudo-loop - in between timeouts the browser then gets a chance to repaint:
var dagaData = ['Manok', 'Pusa', 'Daga', 'Ibon', 'Aso'];
$('#clicktest').on('click', function() {
var i = 0;
(function doNext() {
var item = dagaData[i];
executeData(item);
alert(item);
if (++i < dagaData.length)
setTimeout(doNext, 5);
})();
});
function executeData(item) {
var items = $("<div></div>").text(item);
$('#pangtest').append(items);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button id="clicktest">Test</button>
<div id="pangtest"></div>
Or just use your original $.each() loop with the contents of the loop wrapped in a timeout, as per Bnrdo's answer. But I prefer to wait to schedule each timeout only after the previous one is done because that way the order of execution is guaranteed.

Wrap them in setTimeout
$.each(dagaData, function(index, item) {
setTimeout(function() {
executeData(item);
alert(item);
}, 1);
});

Related

Function doesn't run when I click on the button

So I have a simple JQuery code:
$(function () {
var podatoci;
var i;
$(".front").on("load", init());
$("#remove").on("click", toggleRemove());
function init() {
load();
}
function load() {
$.get("data.json", function (data, status) {
podatoci = data;
fill();
})
}
function toggleRemove() {
console.log("Yes");
$(".likse-dislikes").toggle();
}
function fill() {
for (i = 0; i < podatoci.length; i++) {
$("#container").append("<div class='wrap'><img class='img' src='"+podatoci[i].url+"'/><div class='likes-dislikes'><img class='like' src='sources/like.png'/><img class='dislike' src='sources/dislike.png'/></div></div>");
}
}
});
When I click on the button with ID: remove it runs the toggleRemove() function.
However when I run the web page and when I got to to the console when I click on the button the function doesn't run, instead it does Console.log("OK") only once presumably when the page is loaded. Can anyone please explain where is the problem and how do I fix it?
Thank you in advance!
This doesn't do what you think it does:
$("#remove").on("click", toggleRemove());
This executes toggleRemove once, when the page loads, and sets the handler to the result of that function. (Which is undefined because the function doesn't return anything.)
You want to set the handler to the function itself, not the result of the function:
$("#remove").on("click", toggleRemove);
Additionally, if your element is being added to the page after this code executes (we don't know, though the code shown implies some dynamic elements being added) then you'd need to delegate the event:
$(document).on("click", "#remove", toggleRemove);
You spelled the class name incorrectly on your remove function.
$(".likse-dislikes").toggle();
Change it to
$(".likes-dislikes").toggle();
As I can see here $(".front").on("load", init()); $("#remove").on("click", toggleRemove()); you call your call back in time when you register event listener. Try this: $(".front").on("load", init); $("#remove").on("click", toggleRemove);
You could use $scope.apply(handler)
$scope.apply(function () {
// Angular is now aware that something might of changed
$scope.changeThisForMe = true;
});

why text() function in jquery execute before fadeOut() function

I'm trying to do the following:
Fade out a div
Change its text
Fade it in again
The problem is, step 2 is happening before step 1. Why is that happening?
Here's the code:
<p id="p">
hi!
</p>
<button onclick="foo()">
wefew
</button>
<script>
$("button").click(function (){
var item = $("#p");
item.hide("slow");
item.text("text");
item.show("slow");
})
</script>
https://jsfiddle.net/pq35yd5t/
edit:
I found that the problem is that I'm using a for loop and that the callback function only work on ht elast loop... why, again
code:
for (var i = 0; i < ob_prop.length; i++) {
if (ob_prop[i]=="tag") {
continue;
}
var item = $("#"+ob_prop[i]);
item.hide("slow", function() {
item.text(work[pointer][ob_prop[i]]).show("slow");
});
}
Because fading is an asynchronous operation.
To do what you're doing, use the callback on hide:
$("button").click(function (){
var item = $("#p");
item.hide("slow", function() {
item.text("text");
item.show("slow");
});
})
In a comment you've said:
ok i have tried it but in the original code there's a for loop and function work only at the end of the loop
The callback will have this set to the element related to the callback, so use that rather than item:
$("button").click(function (){
var item = $("#p");
item.hide("slow", function() {
$(this).text("text").show("slow");
});
})
Your latest edit has the closures in loops problem. See that question's answers for details, but one of the solutions is to use $.each (or Array.prototype.forEach if you don't have to worry about obsolete browsers like IE8):
$.each(function(index, ob) {
if (ob != "tag") {
$(ob).hide("slow", function() {
$(this).text(work[pointer][ob]).show("slow");
});
}
});

Javascript + jQuery call same function 4 times correct?

I have a setup where divs that contain similar data (but ranked differently) need to dynamically load data on start up. To do this I load a PHP page through AJAX and pass a parameter so it knows what rank to query. However in order to load on start I need to call the same function 4 times in a row. Is this syntax correct? Or is there a way to write this without a big list of the same function being called
$(document).ready(function(){
getStuff(1);
getStuff(2);
getStuff(3);
getStuff(4);
});
function getStuff(type) {
$.ajax({
type: "GET"
..........
success: function(html) {
$('[data-id="' + type + '"]').html(html);
}
});
}
<div id="rank1" data-id="1"></div>
<div id="rank2" data-id="2"></div>
<div id="rank3" data-id="3"></div>
<div id="rank4" data-id="4"></div>
$(document).ready(function(){
// edit as per taseenb# comment for performance
var size = $("div[id^=rank]").size()
for(var i = 1; i <= size; i++){
getStuff(i);
}
});
Of course there is a way and it is called for loop :)
$(document).ready(function(){
for(i = 1; i < 5; i++){
getStuff(i);
}
});
Why don't you make getStuff take an array and make the AJAX calls in a loop?
Also, something to consider: AJAX is asynchronous (as implied by the name), so there's no guarantee that these calls will return in the same order you make them. If you need them to happen sequentially, you should make the calls recursively--make each subsequent call from the SUCCESS function of the previous call. That way you guarantee that the previous call has finished before you make the next call.
Select via [attribute] selector, iterate via $.each():
$('[data-id]').each(function(){
var $this = $(this);
$.get( '/some/url' {
..........
}).done(function(html){
$this.html(html);
});
})

setTimeout/pausing/ etc

I've tried a few different ways except the right one.
Trying this:
setTimeout( function() {
$('.historyTextBoxes p')
.bind('showText', function(e) {
$(this).fadeIn(800, function(){
$(this).next().length && $(this).next().trigger("showText");
});
}).eq(0).trigger('showText');
}, 4000);
Will wait for 4 seconds, then fade each paragraph in, one after another at the speed of .800 miliseconds.
What I want to do is fade a paragraph in at .800 ms, then wait for 4 seconds before the next paragraph fades in.
The basic set-up of:
$('.historyTextBoxes p')
.bind('showText', function(e) {
$(this).fadeIn(800, function(){
$(this).next().length && $(this).next().trigger("showText");
alert('pause here');
});
}).eq(0).trigger('showText');
works but I've yet to hit the right syntax to make it pause where the alert is.
I tried throwing a call to a function but I don't need to run anything except just to wait.
So in pseudo code, I'm trying to define something like:
function wait() {
pause(for 4 seconds);
}
Then I could just call that function instead of the alert above. My issues with setTimeout has been 'having' to define a function but I'm over thinking something.
Using setTimeout was correct, but you applied it in the wrong place.
$('.historyTextBoxes p').bind('showText',function(e) {
$(this).fadeIn(800,function(){
// this is the callback after the fadein
// here we want to wait (use a timeout)
var next = $(this).next();
if (next.length)
setTimeout(function() {
// before the next text is shown
next.trigger("showText");
}, 4000);
})
}).eq(0).trigger('showText');
This should do it:
function showAll() {
var p = $('.historyTextBoxes p').get(); // array of elements
(function loop() {
if (p.length) {
var el = p.shift();
$(el).fadeIn(800).delay(4000).promise().done(loop);
}
})();
}
demo at http://jsfiddle.net/4dNr3/2/
Note that this uses no explicit timers at all, and nor does it use any events to trigger the next phase - it relies on the animation queue for all timing. Note that it's not generally a good idea to mix timers and animation unless you can guarantee that they're interleaved rather than running in parallel. In this case that's OK, though.

Javascript different variable scope on AJAX call

I have a problem with my variable scope in a simple slider script that I´ve written (I don't want to use a readymade solution because of low-bandwidth). The slider script is called on statically loaded pages (http) as well as on content loaded through AJAX. On the statically loaded page (so no AJAX) the script seems to work perfect. However when called through AJAX the methods called can't find the elements of the DOM, which halts the necessay animation that is needed for the slider.
All the events are handled through even delegation (using jQuery's on() function), this however provided no solution. I'm quite sure it has something to do with the structure and variable scope of the script, but am unable to determine how to change the structure. So I'm looking for a solution that works in both situations (called normal or through AJAX).
I tried to declare the needed variables in every function, this however resulted in some akward bugs, like the multiplication of the intervals I set for the animation, because of the function scope. Hope somebody can help me in the right direction.
// Slider function
(function (window, undefined) {
var console = window.console || undefined, // Prevent a JSLint complaint
doc = window.document,
Slider = window.Slider = window.Slider || {},
$doc = $(doc),
sliderContainer = doc.getElementById('slider_container'),
$sliderContainer = $(sliderContainer),
$sliderContainerWidth = $sliderContainer.width(),
slider = doc.getElementById('slider'),
$slider = $(slider),
$sliderChildren = $slider.children(),
$slideCount = $sliderChildren.size(),
$sliderWidth = $sliderContainerWidth * $slideCount;
$sliderControl = $(doc.getElementById('slider_control')),
$prevButton = $(doc.getElementById('prev')),
$nextButton = $(doc.getElementById('next')),
speed = 2000,
interval,
intervalSpeed = 5000,
throttle = true,
throttleSpeed = 2000;
if (sliderContainer == null) return; // If slider is not found on page return
// Set widths according to the container and amount of children
Slider.setSliderWidth = function () {
$slider.width($sliderWidth);
$sliderChildren.width($sliderContainerWidth);
};
// Does the animation
Slider.move = function (dir) {
// Makes use of variables such as $sliderContainer, $sliderContainer width, etc.
};
// On ajax call
$doc.on('ajaxComplete', document, function () {
Slider.setSliderWidth();
});
// On doc ready
$(document).ready(function () {
Slider.setSliderWidth();
interval = window.setInterval('Slider.move("right")', intervalSpeed);
});
// Handler for previous button
$doc.on('click', '#prev', function (e) {
e.preventDefault();
Slider.move('left');
});
// Handler for next button
$doc.on('click', '#next', function (e) {
e.preventDefault();
Slider.move('right');
});
// Handler for clearing the interval on hover and showing next and pervious button
$doc.on('hover', '#slider_container', function (e) {
if (e.type === 'mouseenter') {
window.clearInterval(interval);
$sliderControl.children().fadeIn(400);
}
});
// Handler for resuming the interval and fading out the controls
$doc.on('hover', '#slider_control', function (e) {
if (e.type !== 'mouseenter') {
interval = window.setInterval('Slider.move("right")', intervalSpeed);
$sliderControl.children().fadeOut(400);
}
});
})(window);
The HTML example structure:
<div id="slider_control">
<a id="next" href="#next"></a>
<a id="prev" href="#prev"></a>
</div>
<div id="slider_container">
<ul id="slider">
<li style="background-color:#f00;">1</li>
<li style="background-color:#282">2</li>
<li style="background-color:#ff0">3</li>
</ul>
</div>
I notice you have
Slider.setSliderWidth = function() {
$slider.width($sliderWidth);
$sliderChildren.width($sliderContainerWidth);
};
which is called on ajax complete.
Does you ajax update the DOM giving a new DOM element that you could get to by doc.getElementById('slider')? Then your var slider and jquery var $slider are likely pointing to things that no longer exist (even if there is a dom element with slider as the id). To rectify, whenever the ajax is invoked that replaces that element, reinitialize slider and $slider to point to the new jquery wrapped element using the same initialization you have.
slider = doc.getElementById('slider');
$slider = $(slider);
Edit:
I'm not sure where you're going with the variable scope issue, but take a look at this example.
<pre>
<script>
(function(){
var a = "something";
function x (){
a += "else";
}
function y() {
a = "donut";
}
function print (){
document.write(a +"\n");
}
print ();
x();
print ();
y();
print ();
x();
print ();
})();
document.write(typeof(a) + "\n");
</script>
</pre>
It outputs into the pre tag
something
somethingelse
donut
donutelse
undefined
This isn't all that different from what you're already doing. As long as a is not a parameter of a method and is not declared with var in a nested scope, all references to a in code defined within your function(window,undefined){ ...} method will refer to that a, given that a is defined locally by var to that method. Make sense?
To begin, surely you can replace all the getElementById using a jQuery approach. i.e. replace $(doc.getElementById('next')) with $('#next')
I think that when you use on it doesn't search the element for the selector as you are assuming. So you would have to use:
$doc.on('click', '#slider_control #prev',function(e){
e.preventDefault();
Slider.move('left');
});
Wait, what gets loaded through Ajax? The slider-html code? In that case, the Slider has already been 'created' and a lot of your variables will point to nowhere (because these DOM elements did not existed when the variables were initialized). And they will never do so either.

Categories