How to delay 5 seconds in JavaScript - javascript

I have JavaScript function:
function validateAddToCartForm(object) {
value = $(".product-detail-qty-box").val();
if(!isInt(value) || value < 1) {
$(".product-detail-error").show();
return false;
} else {
$(".product-detail-error").hide();
var product_name = $("#product_detail_name").text();
var NewDialog = $('<div id="MenuDialog">\ ' + product_name + '</div>');
NewDialog.dialog({
modal: true,
title: "title",
show: 'clip',
hide: {effect: "fadeOut", duration: 1000}
});
}
return true;
}
I need to pause 3 to 5 seconds before returning true, because I want to show a New Dialog box for a while. How can I implement this delay?

The only way to simulate delay in js is callback on timeout.
change the function to:
function validateAddToCartForm(object,callback) {
value = $(".product-detail-qty-box").val();
if(!isInt(value) || value < 1) {
$(".product-detail-error").show();
callback(false);
} else {
$(".product-detail-error").hide();
var product_name = $("#product_detail_name").text();
var NewDialog = $('<div id="MenuDialog">\ ' + product_name + '</div>');
NewDialog.dialog({
modal: true,
title: "title",
show: 'clip',
hide: {effect: "fadeOut", duration: 1000}
});
}
setTimeout(function() {callback(true);},5000);
}
where you call it you should do something like:
instead of
function somefunct() {
//code before call
if (validateAddToCartForm(object)) {
//process true
} else {
//process false
}
//rest of the function
}
place something like:
function somefunct() {
//code before call
validateAddToCartForm(object,function(ret) {
{
if (ret) {
//process true
} else {
//process false
}
//rest of the function
}
}
In to answer to your comment.
I assume:
that you want to prevent click event if validate false,
that all elements that you added onclick="..." have class ".clickme",
the element now looks like
<input type="submit" onclick="return validateAddToCartForm(this)" class="clickme" />
so 1st change the element to
<input type="submit" class="clickme" />
add to your javascript the following:
//this handle original click, drop it out, and only pass after validation
$(function () {
$('.clickme').click(function (e) {
var $t = $(this);
//if event triggered return true
if (e.isTrigger) return true;
validateAddToCartForm(this, function (ret) {
if (ret) {
$t.trigger('click');
}
});
return false;
});
});
also I suggest to use "submit" event on the form itself instead of "click" (the demo of submit)

Instead of blocking, you can use seTimeout to remove the #MenuDialog after a certain time.
function validateAddToCartForm(o){
var keep_dialog_time = 5 * 1000; // five seconds.
// Whatever...
/* Use setTimeout(function, milliseconds) to delay deletion of #MenuDialog.
This will get executed keep_dialog_time milliseconds after this call, and
won't block. */
setTimeout(function(){
$('#MenuDialog').hide(); // maybe there is another function to do this, I'm not a jQuery guy really.
}, keep_dialog_time);
return true;
}
JavaScript is single threaded. This means, when you block, you block the everything. Thus, the DOM uses an event loop model, where callbacks are assigned to events. Such a model is also present in node.js too. Above, because setTimeout does not block, code after that call will continue to run without waiting the function we passed to setTimeout to get executed.
I'd suggest to study DOM in depth to get more comfortable with web front-end programming. You may use various search engines to find out cool documentation.

Related

consume events in the right order

Im using channel's of pusher in a Laravel application.
So when im fired an event from my controller this is received to my client, and with the pusher function I add some text with this lib https://github.com/albburtsev/jquery.typist on my front page:
channel.bind('App\\Events\\TextAdded', function(data) {
if(data.txt){
printPhrase(data.txt);
i++;
}
});
function printPhrase(txt) {
$('<span>')
.addClass('txt_' + i)
.appendTo('.typist_dialog')
.typist({
text:txt,
speed: 15,
}).on('end_type.typist', function() {
console.log('end') ;
}).typistStop() ;
}
});
As you can see I can catch the event "end_type" (when the function stop writing).
The problem is that i cannot -or I've no idea howto- puts "channel.bind" on queue, and so waiting untill that the printPhrase(txt) is finished... so not showing more than one printing for time at screen...
You'll have to set up some sort of queue to make sure they don't fire until the previous one is done. This code isn't tested but should do the trick:
var printQueue = [];
var queueWorking = false;
channel.bind('App\\Events\\TextAdded', function(data) {
if(data.txt){
printQueue.push(data.txt);
workQueue();
}
});
function printPhrase(txt) {
i++;
$('<span>')
.addClass('txt_' + i)
.appendTo('.typist_dialog')
.typist({
text:txt,
speed: 15,
}).on('end_type.typist', function() {
queueWorking = false;
workQueue();
}).typistStop() ;
}
function workQueue(){
if(printQueue.length && !queueWorking){
queueWorking = true;
printPhrase(printQueue.shift());
}
}

Using callbacks JS / JQuery

I am trying to use callbacks in order to effectively "overwrite" the standard alert and confirm actions in JavaScript.
The code I am using is a bit long winded so I jotted it into a working jsfiddle
I am trying to get it so that a callback is used to determine true or false, but it is coming back as undefined as the callback function is fired before a click is
My questions, is how can I change this to effectively overcome the functions value being returned before the click is called via jQuery?
Example usage:
<button onclick="confirm('This is a test')">Show dialog (confirm)</button>
Example jQuery events:
if (confirm("This is a test")) {
alert("Confirmed")
}
else {
alert("Did not confirm")
}
Edit
Using a loop within the callback messed it us a lot...
You are mixing things up when waiting for the return value.
You are passing dialog.checkForInput as the callback. But in the dialog.show() function you do:
var ret = callback();
...
return ret;
But the dialog.checkForInput function doesn't return anything, it merely sets event listeners.
As events all run "asynchronously" it would be more sensible to give your dialog a callback function which will be run when there actually would be an event. Meaning: in your checkForInput function (I would name it differently, but whatever) run the callback and pass the action as a parameter. Something like:
checkForInput: function () {
$(document).ready(function () {
$(".dialog_confirm_okay").on("click", function () {
dialog.hide();
callback('confirm');
})
$(".dialog_confirm_cancel").on("click", function () {
dialog.hide();
callback('cancel');
})
$(".dialog_alert_okay").on("click", function () {
dialog.hide();
callback('alert');
})
})
}
And your callback could look like this (assuming your callback was called dialogCallback):
function dialogCallback ( action ) {
alert('Dialog closed with action: ' + action);
};
Some points I conclude from your code:
The reason why statement callback() return undefined value is because dialog.checkForInput return nothing.
The $(document).ready inside checkForInput is async, so returned value from that block is meaningless (it won't become the return value of the checkForInput as well).
And also you put the return statement inside event declaration, it'll become return value of the event (when the event triggered), not the checkForInput.
I did some modification on your code, this one working. Basically I create new method called onclick, which will be called every time button yes or no is clicked.
show: function (e_type, e_content) {
var d = dialog;
var d_head = e_type == "confirm" ? "Confirm Action" : "Error";
var d_buttons = e_type = "confirm" ? d.parts.buttons.okay + d.parts.buttons.cancel : d.dparts.buttons.alert_okay;
var _dialog = d.parts.main + d.parts.head.replace("{DIV_HEADER}", d_head) + d.parts.body + e_content + "<div class='dialog_button_container'>" + d_buttons + "</div>" + d.parts.footer;
$("body").append(_dialog);
},
onclick: function (ret) {
$(".errors").text("Return value was: " + ret);
},
showError: function (e_content) {
dialog.show("alert", e_content);
dialog.checkForInput();
},
showConfirm: function (e_content) {
dialog.show("confirm", e_content);
dialog.checkForInput();
},
checkForInput: function () {
var self = this;
$(".dialog_confirm_okay").on("click", function () {
dialog.hide();
self.onclick(true);
})
$(".dialog_confirm_no").on("click", function () {
dialog.hide();
self.onclick(false);
})
$(".dialog_alert_okay").on("click", function () {
dialog.hide();
self.onclick(false);
})
},
Working example: https://jsfiddle.net/p83uLeop/1/
Hope this will help you.
EDITED
From the comment section I assume that you want this alert to become a blocking function like window.confirm, so you can do something like if (confirm('Are you sure')).
But sadly it's impossible to achieve this case.
I have some suggestion, you can encapsulate your code better, and implement clean callbacks or promises. Maybe something like this:
showConfirm(function (ok) {
if (ok) {
// "yes" clicked
} else {
// "no" clicked
}
})
// or
showConfirm(function () {
// "yes" clicked
}, function () {
// "no clicked"
})
// or
var customConfirm = showConfirm()
customConfirm.on('yes', function () {
// "yes" clicked
})
customConfirm.on('no', function () {
// "no" clicked
})

control flow and promises

I have a lot of divs in the html. Each div contains animation or some js code which is call only for this div when it visible:
<button id='start' class='start'>Start</button>
<div class="step1 later">
<div class='red later'>Show first</div>
<div class='aqua later'>Show later</div>
</div>
<div class="step2 later">
<div class='green later'>Show together</div>
<div class='yellow later'>Show together</div>
</div>
My goal is show div with step1 class and call some js, then show step2 and so on. It looks like slider. For this example I want show step1 and then show div with red class, after delay I want to show aqua. Next, we go to step2 and show two divs: yellow, green without delay. I have decided to use promises (Q.js) for this. This is my code:
$(function () {
var currentStep = 1,
handlers = {};
$('#start').click(function() {
for(var i = 0; i < 2; i++) {
showStep(currentStep + i);
}
});
function showStep(step) {
var name = 'step' + step;
$('.' + name).show();
handlers[name]();
}
handlers.step1 = function() {
Q().then(function() {
$('.notification').html('Step1 started');
})
.delay(2000)
.then(function() {
showElem('red');
})
.delay(2000)
.then(function() {
showElem('aqua');
});
};
handlers.step2 = function() {
Q().then(function() {
$('.notification').append('Step2 started');
})
.delay(2000)
.then(function() {
showElem('green');
showElem('yellow');
});
};
function showElem(classSelector) {
$('.' + classSelector).fadeIn(100);
}
});
All animations and delay works find except one thing. My code doesn't wait when one step will finish, handlers start almost at the same time.
DEMO : JSBIN
It's rather unconventional to use Q to schedule jQuery actions. With judicious use of its .delay() and .promise() methods, jQuery is well capable of doing this job reliably - on its own.
In the following rewrite of the code :
promises are returned from various functions to allow chaining
the master (start) routine is a simple two-step .then() chain
showElem() and showStep() are unnecessary and disappear
handlers is written as an object literal.
jQuery(function ($) {
var handlers = {
'step1': function() {
$('.notification').html('<div>Step1 started</div>');
return $(".step1").show(0).delay(2000).promise().then(function() {
return $('.red').fadeIn(100).delay(2000).promise();
}).then(function() {
return $('.aqua').fadeIn(100).promise();
});
},
'step2': function() {
$('.notification').append('<div>Step2 started</div>');
return $(".step2").show(0).delay(2000).promise().then(function() {
return $('.green, .yellow').fadeIn(100);
});
}
};
$('#start').click(function() {
handlers.step1().then(handlers.step2);
});
});
DEMO
EDIT
For a large number of handlers, you could longhand out the "start" routine as follows :
$('#start').click(function() {
handlers.step1()
.then(handlers.step2)
.then(handlers.step3)
.then(handlers.step4)
.then(handlers.step5)
.then(handlers.step6)
...
;
});
However, that could be a lot of typing and won't cater for a variable number of handlers.
The solution is reasonably simple.
First, write handlers as an Array, instead of Object.
var handlers = [
//step 0
function() {
$('.notification').html('<div>Step1 started</div>');
return $(".step1").show(0).delay(2000).promise().then(function() {
return $('.red').fadeIn(100).delay(2000).promise();
}).then(function() {
return $('.aqua').fadeIn(100).promise();
});
},
//step 1
function() {
$('.notification').append('<div>Step2 started</div>');
return $(".step2").show(0).delay(2000).promise().then(function() {
return $('.green, .yellow').fadeIn(100);
});
},
//step 2,
...
//step 3,
...
];
Now, you can use Array method .reduce() to scan the array, building a promise chain as it goes :
$('#start').click(function() {
handlers.reduce(function(promise, handler) {
return promise.then(handler);
}, $.when());
});
Here, $.when() is a resolved "seed" promise that gets the chain started.
DEMO
The issue lies in your initial "for" loop, where you execute all your "showStep" in a go, without waiting for promises.
You could do something like that instead:
$('#start').click(function() {
showStep(1);
});
function showStep(step) {
var name = 'step' + step;
$('.' + name).show();
handlers[name]().then(function() {
if (step < 2) {
showStep(step+1);
}
});
}
And make you handlers return the promise.

How can i make a switch button that each click it will do something else?

I'm calling this function from inside a button onclick event:
function pauseSlide() {
clearInterval(sint);
setInterval(slideUpdate, 1000); paused(clearInterval)
}
And i want that on the first click to do the clearInterval(sint);
And if i click on the button again then only do the setInterval(slideUpdate, 1000);
Like a switch.
In csharp for example you do it like this: CelsiusFahrenheit = !CelsiusFarenheit;
So one click the boolean CelsiusFahrenheit is true and next click it's false then again true and so on....
This is the javascript button onclick event:
var
slideShow = d.getElementById('slideShow'),
slideCounter = make('div', false, {id: 'slideCounter'}),
slideControls = make('div', false, {id: 'slideControls'}),
slidePrev = make('a', 'Previous Slide', {
onclick: function (e) {
controlEvent(e, prevSlide);
},
className: 'previous',
href: '#'
}, slideControls),
slideNext = make('a', 'Next Slide', {
onclick: function (e) {
controlEvent(e, nextSlide);
},
className: 'next',
href: '#'
}, slideControls),
slidePause = make('a', 'Pause Slide', {
onclick: function (e) {
controlEvent(e, pauseSlide);
},
className: 'pause',
href: '#'
}, slideControls)
I did that if i click the Pause Slide button it will call the function pauseSlide
And inside pauseSlide i want to make the switch one click to call clearInterval another click will call setInterval.
I have this function also:
function slideUpdate() {
if (swapCounter--)
showCounter();
else
nextSlide();
}
And if i click the button a lot it's just making the countdown to move faster each time.
If it will help or needed this is the complete code with all buttons events:
JS
There are probably a few ways to do this. The best is probably to keep a boolean variable such as "isPaused" and flip that back and forth as needed. Wrap your click logic in a conditional dependent on that variable.
BTW you can't detect whether an interval is running or has been cleared. Even if you could, it would be harder to read and understand what was going on. I'd prefer a semantic variable as described above.
This is example of handle multiactions in loop, main idea is to place actions to array and shift/push them to cycle.
var actions = [
function () {
console.log(1);
$(this).next().fadeOut(100);
},
function () {
console.log(2);
$(this).next().fadeIn(100);
},
function () {
console.log(3);
$(this).next().slideUp();
},
function () {
console.log(4);
$(this).next().slideDown();
}];
$('.multiact').each(function (i, e) {
$(e).data('actions', actions.concat());
}).click(function (e) {
var acts = $(this).data('actions'),
act = acts.shift();
acts.push(act);
act.call(this, e);
});
http://jsfiddle.net/8tgxpedq/2/
var prevClicked = false;
var my_slide_timer;
function pauseSlide() {
if(!prevClicked){
clearInterval(my_slide_timer);
prevClicked = true;
}else{
my_slide_timer = setInterval(slideUpdate, period);
prevClicked = false;
}
}
This did the trick.

jQuery adding functions to the animation queue

The problem is that when I try doing multiple animations they all happen the same time.
Is there any way to have animations go one after another without using callbacks?
Here's what I want to do:
$('#a1').click(function() { $('#div1').hide(3000); });
$('#a2').click(function() { $('#div2').hide(3000); });
$('#a3').click(function() { $('#div3').show(3000); });
If you click on #a1 and then click on #a2 then #a3 before the first animation completes then it shouldn't start right away but instead wait until the animation queue is empty then start the next one.
Take this demo for example
I want to be able to click a1 then a2 then a3 one after the another and first have it hide the first div completely, then the second completely, and then show the third.
My example is overly simple and while this can be done with callbacks, my real problem can't so callbacks aren't an option.
In essence, if you click all three the animation should complete in 9 seconds.
This DEMO should alert ('took around 9 seconds to complete')
Use .queue() on a common jQuery object:
var q = $({}); // this could also be a common parent, e.g. $('body')
$('#a1').click(function() {
q.queue(function(next) {
$('#div1').hide(3000, next);
});
return false;
});
$('#a2').click(function() {
q.queue(function(next) {
$('#div2').hide(3000, next);
});
return false;
});
$('#a3').click(function() {
q.queue(function(next) {
$('#div3').show(3000, next);
});
return false;
});​
Demo
Use .promise() to sidestep callbacks on show and hide:
The .promise() method returns a dynamically generated Promise that is resolved once all actions of a certain type bound to the collection, queued or not, have ended.
By default, type is "fx", which means the returned Promise is resolved when all animations of the selected elements have completed
Use .queue() to limit the number of animations resolved per promise (See also jsFiddle):
var promises = $({});
$('#a1').click(function() {
promises.queue(function(next) {
$('div').promise().done(function() {
$('#div1').hide(3000);
next();
});
});
return false;
});
$('#a2').click(function() {
promises.queue(function(next) {
$('div').promise().done(function() {
$('#div2').hide(3000);
next();
});
});
return false;
});
$('#a3').click(function() {
promises.queue(function(next) {
$('div').promise().done(function() {
$('#div3').show(3000);
next();
});
});
return false;
});
Try to create some array with queue, and check if there is something in it, as callback for animation, and run it again if there is. I've played with your example a little.
check it out:
http://jsfiddle.net/acrashik/nqh6x/6/
var queue = {
q: [],
run: function(elem, type, time, recall) {
if (queue.isRunning && !recall) {
console.log('pushed: ' + elem + type + time);
queue.q.push({elem:elem, type:type, time:time});
} else {
console.log('running:' + elem);
queue.isRunning = true;
if (type=='hide') {
$(elem).hide(time, function(){
queue.recall();
})
} else {
$(elem).show(time, function(){
queue.recall();
})
}
}
},
recall: function(){
console.log(queue.q.length);
if (queue.q.length > 0) {
queue.run(queue.q[0].elem, queue.q[0].type, queue.q[0].time, true);
queue.q = queue.q.splice(1,queue.q.length);
} else {
queue.isRunning = false;
queue.q = [];
}
},
isRunning: false
}
$('#a1').click(function() { queue.run('#div1','hide',2200) });
$('#a2').click(function() { queue.run('#div2','hide',2200) });
$('#a3').click(function() { queue.run('#div3','show',2200) });
I would use the animate() function as it comes with a complete function which is called when the animation finishes http://api.jquery.com/animate/.
So to use the jQuery doc example:
$('#clickme').click(function() {
$('#book').animate({
opacity: 0.25,
left: '+=50',
height: 'toggle'
}, 5000, function() {
// Animation complete this is where you call the next animation...
});
});
function another_animation () {
$('xyz').animate({
opacity: 0.25,
left: '+=50',
}5000, function() {
// Animation complete this is where you call the next animation
I think that this is the cleanest way...
You could do something like this:
(function(){
var col=(function(){
var i=1;
return function(n){alert("you clicked link nr " + n + ", total clicks: "+i++)};
})();
$('#a1').click(function(){col(1)});
$('#a2').click(function(){col(2)});
$('#a3').click(function(){col(3)});
})();
Im not gona write the entire code for you but that should give you a good idea of how to do it.
Also none of the variables or functions are accessible from the global scope or any other.
Add stop() before the animation:
$('#a1').click(function() { $('#div1').stop().hide(3000); });
$('#a2').click(function() { $('#div2').stop().hide(3000); });
$('#a3').click(function() { $('#div3').stop().show(3000); });
Use this
$(element).promise().done(function () {...})
In your case
$('#a1').click(function () {
$('#div1').hide(3000);
});
$('#a2').click(function () {
$("#div1").promise().done(function () {
$('#div2').hide(3000);
});
});
$('#a3').click(function () {
$("#div2").promise().done(function () {
$('#div3').hide(3000);
});
});
The next animation will be performed only when the previous animation on selected element is complete.

Categories

Resources