Why is this wrong? (use of "this" with jQuery) - javascript

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.js"></script>
<script type="text/javascript">
function bigtosmalltriangle() {
$(this).siblings("div.break").removeClass('triangle3').addClass('triangle1');
setTimeout ( "smalltomediumtriangle()", 400 );
}
function smalltomediumtriangle() {
$(this).siblings("div.break").removeClass('triangle1').addClass('triangle2');
setTimeout ( "mediumtobigtriangle()", 400 );
}
function mediumtobigtriangle() {
$(this).siblings("div.break").removeClass('triangle2').addClass('triangle3');
setTimeout ( "bigtosmalltriangle()", 400 );
}
$(function() {
$("span#clickhere").click(
function() {
/* do a lot stuff here */ bigtosmalltriangle();
$(this).hide();
}
);
});
</script>
<style type="text/css">
.triangle1 {background:#000;}
.triangle2 {background:red;}
.triangle3 {background:white;}
</style>
<div><div class="break">Hello World</div><span id="clickhere">asdf</span></div>
I'm trying to get get the div.break to scroll through 3 bgcolors, but when I click on the span it has no effect. Does anyone know what I should do?
Thanks.

You want to call your functions with a specific "this". I asked a similar question: Call function with "this".
$(function() {
$("span#clickhere").click(
function() {
/* do a lot stuff here */
bigtosmalltriangle.call(this);
$(this).hide();
}
);
});
I think because of closures (see Matthew Crumley's answer) the callback functions themselves don't need to be modified, because setTimeout keeps the "scope." I don't know Javascript enough to remotely guarantee that, though. If I am wrong, simply perform the .call(this) trick for the callback functions as well.

The problem is that "this" is not bound to the span you clicked on in the bigtosmalltriangle, smalltomediumtriangle, and mediumtobigtriangle functions. You need to either pass in the element as a parameter, or set a variable that's in scope in all the functions through closures.
Parameter passing:
function bigtosmalltriangle(elements) {
elements.removeClass('triangle3').addClass('triangle1');
setTimeout(function() { smalltomediumtriangle(elements); }, 400);
}
function smalltomediumtriangle(elements) {
elements.removeClass('triangle1').addClass('triangle2');
setTimeout(function() { mediumtobigtriangle(elements); }, 400);
}
function mediumtobigtriangle(elements) {
elements.removeClass('triangle2').addClass('triangle3');
setTimeout(function() { bigtosmalltriangle(elements); }, 400);
}
$(function() {
$("span#clickhere").click(
function() {
/* do a lot stuff here */
bigtosmalltriangle($(this).siblings("div.break"));
$(this).hide();
}
);
});
Closures:
$(function() {
$("span#clickhere").click(
function() {
var elements = $(this).siblings("div.break");
function bigtosmalltriangle() {
elements.removeClass('triangle3').addClass('triangle1');
setTimeout(smalltomediumtriangle, 400);
}
function smalltomediumtriangle() {
elements.removeClass('triangle1').addClass('triangle2');
setTimeout(mediumtobigtriangle, 400);
}
function mediumtobigtriangle() {
elements.removeClass('triangle2').addClass('triangle3');
setTimeout(bigtosmalltriangle, 400);
}
/* do a lot stuff here */
bigtosmalltriangle();
$(this).hide();
}
);
});

Related

Convert $(document).ready() function into window.onload function?

I have a jQuery function :
$(document).ready(function() {
setInterval(function() {
$.post("../user/getdashboard/", function(data) {
$("#users_available").html(data);
});
}, 3000);
}
I have to convert it into window.onload function.
How to do it?
If you want it vanilla js, use onload callback of the window object:
window.onload = function() {
setInterval(function() {
$.post("../user/getdashboard/", function(data) {
$("#users_available" ).html(data);
});
}, 3000);
}
But you could even use load event with jQuery, what is basically the same:
$(window).on('load', function() {
setInterval(function() {
$.post("../user/getdashboard/", function(data) {
$("#users_available").html(data);
});
}, 3000);
});
But keep in mind, that a jQuery ready state is not the same as window.onload. These are two different things. So this might have unexpected impacts to your project/page.
You can handle the readystatechange event,
document.onreadystatechange = function () {
if (document.readyState === "interactive") {
// Your code
}
}
window.onload waits for everything, including images, which probably is overkill.

JQuery: Wait until all fadeout`s of function are finished

I have next function:
function clearWorkingArea() {
$('.extensionText').children('span').fadeOut(600, function() { $(this).remove() });
$('ul.texts').fadeOut(600, function() { $(this).empty() });
$('.buttonsDiv').fadeOut(600, function() { $(this).remove() });
$('.processingDiv').fadeOut(600, function() { $(this).remove() });
}
I would like to call another function only after all animations in this function are finished.
I tried :
$.when(clearWorkingArea()).done(function() {...});
Also:
clearWorkingArea().promise().done(function() {...});
No luck, it is still not working properly.
Is there is a way, instead of callback hell of fades, to do such function behavior?
Update: just double checked jquery, animations can return a promise. I initially just did promise, but to get a promise with jquery you do promise(). So you don't need the helper function after all.
Below is an example.
Also if you have multiple selectors doing the same thing, you can combine.
eg. below .two & .three fadeOut at 600ms, but I've made .one fadeOut over 1000ms. Also added a none-existent selector to make sure things still work.
Promise.all(
[
$('.one').fadeOut(1000, function () {
$(this).empty(); }).promise(),
$('.two,.three').fadeOut(600, function () {
$(this).empty(); }).promise(),
$('.not-exist').fadeOut(600, function () {
$(this).empty(); }).promise()
]
).then(function () {
console.log('all done');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="one">
Three 1000 ms
</div>
<div class="two">
One 600 ms
</div>
<div class="three">
Two 600 ms
</div>
clearWorkingArea only starts the animations, but these animations are all async.
At the end of clearWorkingArea, your animations are unlikely to be over.
You have to fetch a promise for each animation and then use Promise.all to trigger your code when all promises are over.
According to the documentation, you can get the promise by using the start parameter in the options of fadeOut like methods:
jQuery fadeOut()
Hope this helps!
How about we apply some simple logic like this.
function doWorkWhenAllFinished(counter) {
if (counter == 4) {
//All fade animations have been complete.
//Good to go...
}
}
function clearWorkingArea() {
var counter = 0;
$('.extensionText').children('span').fadeOut(600, function() {
counter++;
$(this).remove();
doWorkWhenAllFinished(counter);
});
$('ul.texts').fadeOut(600, function() {
counter++;
$(this).empty();
doWorkWhenAllFinished(counter);
});
$('.buttonsDiv').fadeOut(600, function() {
counter++;
$(this).remove();
doWorkWhenAllFinished(counter);
});
$('.processingDiv').fadeOut(600, function() {
counter++;
$(this).remove();
doWorkWhenAllFinished(counter);
});
}

Consolidate javascript timeout functions

Sorry for the basic level of the question, but js definitely isn't my area of expertise. However, it's one of those questions that's difficult to Google an answer on.
I basically want to do a couple of things when the window is resized. I have a little bit of extra code that also stops the resize event firing twice.
The issue is that I'm duplicating bits of code, that as a coder, I know is wrong. The problem is I don't know how to go about making it right. Here's my current duplicated code:
Event binding
$(window).on("resize", resizeText);
$(window).on("resize", resizeIndicator);
Functions
function resizeIndicator() {
clearTimeout(id);
id = setTimeout(updateIndicator, 200);
}
function resizeText() {
clearTimeout(id);
id = setTimeout(updateText, 200);
}
Thse are not duplicated but included for completeness:
function updateIndicator() {
$tab = $(".tabs li.focus");
if ($tab.length) {
toggleIndicator($tab, true);
}
}
function updateText() {
$tabs = $(".tabs li:not(.indicator) a");
$tabs.each(function () {
$(this).toggleClass("two-line", this.scrollWidth > $(this).outerWidth());
});
}
So you want to avoid code duplication? No problem use higher order of function to create new function.
function createResizeCallback(resizeFunc) {
var id;
return function () {
clearTimeout(id);
id = setTimeout(resizeFunc, 200);
}
}
$(window).on("resize", createResizeCallback(updateText));
$(window).on("resize", createResizeCallback(updateIndicator));
function updateIndicator() {
console.log('updateIndicator');
}
function updateText() {
console.log('updateText');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Declare your timeout id globally and use single handler.
Working demo: http://jsbin.com/nugutujoli/1/edit?js,console,output
$(window).on("resize", resizeEvent);
var timeout;
function resizeEvent() {
clearTimeout(timeout);
timeout = setTimeout(function(){
updateIndicator();
updateText();
}, 200);
}
function updateIndicator() {
console.log("update indicator fired.");
}
function updateText() {
console.log("update text fired.");
}

how to make jquery infinite loop

this is my jquery code.this code contain three functions.this three function repeatedly execute for looping.but this code not run properly.how to make recursive call with three functions.the pid1,pid2,pid3 is paragraph tag id's.this code used to make text animation.
$(document).ready(function(){
function animate()
{
$('#pid1').fadeOut(3000, function()
{
$(this).text('string1').fadeIn(3000);
});
animate1();
}
function animate1()
{
$('#pid2').fadeOut(3000, function()
{
$(this).text('string2').fadeIn(3000);
});
animate2();
}
function animate2()
{
$('#pid3').fadeOut(3000, function()
{
$(this).text('string3').fadeIn(3000);
});
animate();
}
});
try like this :
$(document).ready(function(){
function animate() {
$.when($('#pid1').fadeOut(3000, function() {
$(this).text('string1').fadeIn(3000);
})).then(function() {
animate1();
});
}
function animate1() {
$.when($('#pid2').fadeOut(3000, function() {
$(this).text('string2').fadeIn(3000);
})).then(function() {
animate2();
});
}
function animate2() {
$.when($('#pid3').fadeOut(3000, function() {
$(this).text('string3').fadeIn(3000);
})).then(function() {
animate();
});
}
animate();
});
Here a jsFiddle : http://jsfiddle.net/Pascalz/CNRSd/
You must call the function again after making sure that element has fadeout. You should use fadeout callback functions
change you function like this:
function animate()
{
$('#pid1').fadeOut(3000, function()
{
$(this).text('string1').fadeIn(3000, function(){animate(); });
});
}
Here is the link of jsbin by using callback functions
animate by using callback

Execute function after async function is done

How to make function extra_stuff to be executed after anim or display_effects functions are done ? Best option would be to hold function extra_stuff until animate is done because i don't want to edit anonymous function passed to on method, it should stay simple and readable.
<html>
<head>
<meta charset="utf-8">
<script src="jquery-2.0.3.min.js"></script>
<style>
.selected {color:pink;}
</style>
</head>
<body>
<ul id="workers">
<li>worker#1</li>
<li>worker#2</li>
<li>worker#3</li>
<li>worker#4</li>
</ul>
<script>
$(function()
{
function unmark_selected()
{
$('.selected').removeClass('selected');
}
function mark_user(e)
{
e.addClass('selected');
}
function display_effects(e)
{
e.animate({ fontSize: "24px" }, 1500);
}
function extra_stuff()
{
console.log('maybe another animation');
}
$('ul#workers li a').on('click', function()
{
unmark_selected();
mark_user( $(this) );
display_effects( $(this) );
extra_stuff();
});
});
</script>
</body>
</html>
Make display_effects to return a promise() object, and then call the extra_stuff method in the done callback of the promise
$(function () {
function unmark_selected() {
$('.selected').removeClass('selected');
}
function mark_user(e) {
e.addClass('selected');
}
function display_effects(e) {
return e.animate({
fontSize: "24px"
}, 1500).promise();
}
function extra_stuff() {
console.log('maybe another animation');
}
$('ul#workers li a').on('click', function () {
unmark_selected();
mark_user($(this));
display_effects($(this)).done(extra_stuff);
});
});
You need a callback:
function display_effects(e, callback) {
e.animate({ fontSize: "24px" }, 1500, callback);
}
$('ul#workers li a').on('click', function() {
unmark_selected();
mark_user( $(this) );
display_effects( $(this), extra_stuff ); // no invocation, pass reference!
});
It will be called in the future, when the fontsize animation is done. Check the docs for the .animate() method. Notice that if you simply want to add another animation after the fontsize, they will be queued automatically.

Categories