Function not accepting callback - javascript

My goal is to show and hide a search form and a call number. When the search form is visible, the toggle should allow the form to submit. They shouldn't be open at the same time because there isn't room for both of them to be open, so I've written the functions to accept callback functions except both events seem to fire at the same time, ignoring the fact that they should wait for the first function to complete.
What am I doing wrong? My code is pasted below, but here's a fiddle that demonstrates the problem. There may also be a better way to write this so I'm open to suggestions. Thanks.
//Functions for Search and Call
var closeSearch = function(callback) {
$('.searchbox').removeClass('open').addClass('notOpen').animate({
width: '40px'
}, function() {
$('.call').animate({
width: '100%'
}, function() {
$('.call h4').fadeIn();
});
$('.search_bar').hide();
});
if (typeof callback == "function") {
callback();
}
};
var openSearch = function(callback) {
$('.searchbox').animate({
width: '100%'
}).addClass('open').removeClass('notOpen');
$('.search_bar').animate({
width: '100%'
}).fadeIn();
$('.search_bar #searchform .search-query').animate({
width: '90%'
});
if (typeof callback == "function") {
callback();
}
};
var closeCall = function(callback) {
$('.call').removeClass('open').addClass('notOpen')
$('.call').animate({
width: '60px'
});
$('.call h4').fadeOut();
if (typeof callback == "function") {
callback();
}
};
var openCall = function(callback) {
$('.call').animate({
width: '100%'
}, function() {
$('.call h4').fadeIn();
});
$('.searchbox').addClass('notOpen');
if (typeof callback == "function") {
callback();
}
};
// Search Box Toggle
$('.searchbox a').toggle(function() {
if ($('.searchbox').hasClass('notOpen')) {
closeCall(function() {
openSearch();
});
} else {
$('.search_bar #searchform').submit();
}
}, function() {
if ($('.searchbox').hasClass('notOpen')) {
closeCall(function() {
openSearch();
});
} else {
$('.search_bar #searchform').submit();
}
});
//Call Box Toggle
$('.call a').toggle(function() {
if ($('.searchbox').hasClass('open')) {
closeSearch(function() {
openCall();
});
} else {
openCall();
}
}, function() {
if ($('.searchbox').hasClass('open')) {
closeSearch(function() {
openCall();
});
} else {
closeCall();
}
});​

As the animations themselves need some time to execute, they run asynchronous, thus providing their own callback - method.
In your script, you put your callback-function right after calling animate, so your passed function is called immediatly. You should put the call of your own callback - function into the callback-function of the jQuery animation.
For example:
$('.searchbox').animate({
width: '100%'
}, function(){
//callback of the .animate-function
if (typeof callback == "function") {
callback();
}
});
I made a quick edit to your fiddle to show you: http://jsfiddle.net/nsSxh/2/
I know it's not perfect, but it should give you an idea what to do.

Related

Accessing a function within a function inside object literals in javascript?

I have some code as follows -
var app = {
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
document.addEventListener('backbutton',this.receivedEvent.backbutton(),false);
^-- //not working
},
onDeviceReady: function() {
this.receivedEvent('deviceready');
},
receivedEvent: function(id) {
var originalLocation, partnership;
function fadeOut(element, direction) {
....
};
function fadeIn(element, direction) {
.....
}
function formFadeIn(direction) {
fadeIn($("#dataform"), direction);
};
function formFadeOut(direction) {
fadeOut($("#dataform"), direction);
};
function backbutton () {
var current = $("#home").attr("page-current");
var prev = $("#home").attr("page-prev");
if (current == "dataform" && prev == "partnertype") {
formFadeOut("opposite");
partnertypeFadeIn("opposite");
setPage("country", "partnertype")
$("#selectcountry").attr("disabled", false).val("AF")
} else if (current == "dataform" && prev == "country") {
formFadeOut("opposite");
countryFadeIn("opposite");
} else if (current == "partnertype" && prev == "country") {
partnertypeFadeOut("opposite");
countryFadeIn("opposite");
} else {
window.location.reload()
}
}
}
};
app.initialize();
So I need to bind the event "backbutton" to the function backbutton() within receivedEvent. function backbutton() is invoking local functions within receivedEvent such as formFadeIn() etc.
I am unable to figure out the exact syntax on binding.
What I've tried -
this.receivedEvent.backbutton //no response
this.receivedEvent.backbutton() //no response
this.receivedEvent.bind(this).backbutton //causes infinite looping on the page
exporting the backbutton() function as return { backbutton : backbutton } //no response
What do I have to do to access function backbutton() from app.initialize() without loosing context?
You could try :
var app = {
initialize: function() {
document.addEventListener('backbutton',this.myBackButtonFunction, false);
},
myBackButtonFunction: function() {
// Your code
}
receivedEvent: function(id) {
// Can also be invoked from here
this.myBackButtonFunction();
},
};
app.initialize();

custom when statement not firing functions

I am trying to make a when statement but it is not working as planned. Basically its a function to call another function when try. First before I explain further here is the syntax
when(function() {
//code here
});
Now basically... Think this way.. We have a progressbar.. We also have a custom event such as...
var pBarEvent = document.createEvent('Event');
pBarEvent.initEvent('pbardone', true, true);
document.addEventListener('pbardone', function() {
//code here
});
//if progress bar reaches 100 dispatchEvent
if (document.querySelector(".progress-bar").style.width === 100 + "%")
{
document.dispatchEvent(pBarEvent);
}
Now that piece of code is an example. If the document loads and its for instance at 50% it wont trigger until you add another event such as keydown or click. I dont want to do that I want to do.... "when" progress bar width equals 100% trigger it. Thats basically what needs to happen. So here is the code for the when statement so far (keep in mind its not the best looking one. As I dont normally do this but I wanted to keep this dynamic and who knows someone who later wants to do this can look at this question)
when function
function when(func)
{
var nowActive = false;
if (!typeof func === 'undefined')
{
func = new Function();
}
if (func)
{
nowActive = true;
clearInterval(whenStatementTimer);
}
else
{
nowActive = false;
var whenStatementTimer = setInterval(function() {
switch(func)
{
case true:
{
nowActive = true;
when();
break;
}
case false:
{
nowActive = false;
when();
break;
}
}
}, 1000);
}
if (nowActive === true)
{
func();
}
}
Now this does not work when I go to try something like....
when(function() {
SmartLeadJS.SmartLeadEvents.customEvents.progressBarFull(function() {
alert("100%");
SmartLeadJS.SmartLeadAds.LeadView.ChromeExtension.General.DynamicStyles.$.style("body", "background", "black");
});
});
It does not trigger. I need help possibly getting this when statement to work. What am I doing wrong? What can I do to fix it? No errors get thrown but it never fires.
edit based on answer
Function tried
function when(currentValue)
{
try
{
var o = {};
o.currentValue = currentValue;
o.do = function(func)
{
if (!typeof func === 'undefined')
{
func = new Function();
}
if (this.currentValue)
{
func();
}
else
{
setTimeout(this.do(func), 100);
}
};
return o;
}
catch(e)
{
console.log(e);
}
}
used as
when(true).do(function() {
SmartLeadJS.SmartLeadEvents.customEvents.progressBarFull(function() {
alert("This divs going through changes!!");
SmartLeadJS.SmartLeadAds.LeadView.ChromeExtension.General.DynamicStyles.$.style(".div", "background", "black");
});
});
This does not work. It never fires. But if I use a onclick listener as such it fires
document.addEventListener("click", function() {
SmartLeadJS.SmartLeadEvents.customEvents.progressBarFull(function() {
alert("This divs going through changes!!");
SmartLeadJS.SmartLeadAds.LeadView.ChromeExtension.General.DynamicStyles.$.style(".div", "background", "black");
});
}, false);
function when(statement){
o={};
o.statement=statement;
o.do=function(func){
awhen(this.statement,func);
};
return o;
}
function awhen(statement,func){
if(eval(statement)){
func();
}else{
window.setTimeout(function(){awhen(statement,func);},100);
}
}
Use:
when("true").do(function(){});
It works now :) . Its important to put the condition in ""!

End a script 1 second after the first scripts finishes

I want to run an animation function after another function (handleScreen) has completed. The animation function will fade out parts of the page after 1 sec. I tried adding a .promise function but that doesn't seem to work.
https://jsfiddle.net/Dar_T/eqdk82ru/1/
handleScreen(mql).promise().done(function() {
setTimeout(function() {
$("#name,#splash").fadeOut("slow");
}, 1000);
});
You can use jquery Deferred object to resolve this:
handleScreen creates a $.Deferred that will be passed to the animation function. A promise from this deferred is then returned.
function handleScreen(mql) {
var def = $.Deferred();
mql.matches ? smallBlock(def) : largeBlock(def);
return def.promise();
}
The animation function marks the deferred as resolved once the animation finishes (using TweenLite onComplete argument on the last animation):
function largeBlock(def) {
setTimeout(function () {
TweenLite.defaultEase = Linear.easeNone;
TweenLite.set('.square', { visibility: 'visible' });
var tl = new TimelineLite();
tl.fromTo('.l1', 2, { height: 0 }, { height: 227 });
tl.fromTo('.l2', 3, { width: 0, }, { width: 445 });
tl.fromTo('.l3', 2, { height: 0 }, { height: 227 });
tl.fromTo('.l4', 3, { width: 0 }, { width: 445, onComplete: def.resolve });
tl.timeScale(4);
}, 600);
}
fadeOut is executed once the deferred is done:
handleScreen(mql).done(function() {
setTimeout(function() {
$("#name,#splash").fadeOut("slow");
}, 1000);
});
});
Demo: https://jsfiddle.net/g5f7pex3/1/
A simple approach that addresses the problem in a different way than you were thinking:
var alreadyFaded = false;
function FadeSplash()
{
if(alreadyFaded == false){
//prevent this from running a second time
alreadyFaded = true;
$("#name,#splash").fadeOut("slow");
}
}
$(function () {
//do something
//make the fade happen upon finishing if it hasn't already
FadeSplash();
});
$(function () {
//by default, the fade will happen after 5 seconds if FadeSplash()
//wasn't already called by the above function.
$("#splash,#name").show(), setTimeout(function () {
FadeSplash();
}, 5000)
});
Here's a working JSFiddle to demonstrate:
https://jsfiddle.net/tthhaft1/
Short answer: you can't do it naturally. Long Answer: use an interval to check for a flag, also, there is no need for 2 document ready:
$(document).ready(function () {
var finished = false;
SOME FUNCTION
//Inside SOME FUNCTION do your stuff, and before returning or whatever it is doing:
var intervalCheck = setInterval(function () {
if (finished) {
//Do your stuff you need to do after those 5 secs.
clearInterval(intervalCheck);
}
}, 1000);
$("#splash,#name").show(), setTimeout(function () {
$("#name,#splash").fadeOut("slow")
finished = true;
}, 5000);
});

jQuery plugin: prevent multiply calls of an object

Recently, I'm writing a jQuery plugin which moves html elements.
My plugin is something like this:
$('#div1').moveIt({ top: 100, left: 200 });
The problem is, When I call moveIt more than once for an element. It does all methods together. something like this:
$('#div1').moveIt({ top: 100, left: 200 }); // first call
$('#div1').moveIt({ top: 200, left: 300 }); // second call
// even more calls ....
The questions are:
How can I prevent the the second call inside my plugin?
How can I overwrite the new values of second call into the first call?
A simple sample code will be enough.
edit: here is my problem
UPDATED: What about your problem - check fiddle http://jsfiddle.net/vittore/jHzLN/1/
You have to save timeout and clear it when you set new one.
What you are asking for is called throttle.
Check this article http://benalman.com/projects/jquery-throttle-debounce-plugin/
But as you are really using jquery animations ( your plugin name tells that ), you have to use something else.
Check stop() method
$(selector).stop(true, true).animate(...)
Another interesting thing you can do is queue additional animations. Use queue:true option for that:
$(selector).animate({ left:...} , { queue: true })
Is this what you were going for? http://jsfiddle.net/acbabis/B89Bx/. Let me know:
$(function()
{
var methods =
{
init : function(options) {
$(this).each(function() {
var self = $(this);
var settings = $.extend({
top : 50,
left : 50,
dir : true,
}, options);
var i=0, j=0;
var move = function()
{
settings = self.data('moveItTarget');
if(settings.dir)
{
i++;
j++;
}
else
{
i+=10;
j+=10;
}
self.css({'top':Math.min(i, settings.top),
'left':Math.min(j, settings.left)});
if(j<=settings.top && i<=settings.top)
{
setTimeout(move,1);
} else {
self.data('movingIt', false);
}
};
self.data('moveItTarget', settings);
if(!self.data('movingIt')) {
self.data('movingIt', true);
move();
}
});
}
};
$.fn.moveIt = function(methodOrOptions) {
if (methods[methodOrOptions]) {
return methods[methodOrOptions].apply(this,
Array.prototype.slice.call(arguments, 1));
} else if (typeof methodOrOptions==='object' || !methodOrOptions) {
return methods.init.apply(this, arguments);
} else {
$.error('Method "'+methodOrOptions+'" does not exist!');
}
};
}(jQuery));
$('#div1').moveIt({ top: 100, left: 100, dir: true }); // first call
$('#div1').moveIt({ top: 300, left: 300, dir: false }); // second call

Recursive function : where am I wrong here?

Code :
isDomLoaded = $(function () {
setTimeout(function () {
if (renderFinished) {
renderSocial(fotoProssima);
} else {
isDomLoaded();
}
}, 300);
});
it says isDomLoaded is not a function
Thats because it isn't a function. It is a jQuery object.
What you need might be:
isDomLoaded = function () {
setTimeout(function () {
if (renderFinished) {
renderSocial(fotoProssima);
} else {
isDomLoaded();
}
}, 300);
};
If you want to run it when the DOM is ready then do this after you declare the function:
$(window).load(isDomLoaded);
However, I think what you really need is to get rid of the isDomLoaded function and just use the following:
$(document).ready(function(){
renderSocial(fotoProssima);
});
function isDomLoaded(){
//code
//recursive call
isDomLoaded();
}

Categories