function within a function javascript logical error - javascript

I'm unable to figure out where a syntax logical error resides in the script furthest below. Essentially what it does is it alerts people that they must wait 1.5 seconds before they can answer a radio-button type question and automatically move on to the next page. No alert if they spend more than 1.5 seconds.
This script was written for only one click event, but I need it to work for two nested events, where clicking on a radio button option automatically triggers the "next" button to move on to the next page. For example if you take out the following event (and its end brackets), it works well:
$("[class*=bfasg] .radio").click(function(){
I've checked the syntax at Esprima to make sure the brackets are correct, so the problem lies elsewhere.
$(document).ready(function() {
minTime(1.5);
function minTime(minTime) {
var startTime = new Date();
$("[class*=bfasg] .radio").click(function(){$("#movenextbtn").click(function(){
var endTime = new Date();
if((endTime - startTime)/1000 <= minTime) {
alert('You must spend at least '+minTime+' seconds on the question.');
return false;
}
else {
return true;
}
});
});
}
});
Any experts out there who can detect the problem?

(See answer to updated question below)
It's not a syntax error. It's a logic error.
It becomes slightly clearer if you format the code consistently:
$(document).ready(function () {
minTime(1.5);
function minTime(minTime) {
var startTime = new Date();
// Hooking up a click handler
$("[class*=bfasg] .radio").click(function () {
// This code doesn't run until/unless someone clicks
// one of the `[class*=bfasg] .radio` elements.
$("#movenextbtn").click(function () {
var endTime = new Date();
if ((endTime - startTime) / 1000 <= minTime) {
alert('You must spend at least ' + minTime + ' seconds on the question.');
return false;
} else {
return true;
}
});
});
}
});
What you've done there is said "When someone clicks a [class*=bfasg] .radio element, hook up an event handler on the #movenextbtn element."
You probably don't want to wait to hook up the event until someone clicks on a radio button. If your goal is to hook up the click event on both sets of elements, combine them in the same selector as you would in CSS:
$(document).ready(function () {
minTime(1.5);
function minTime(minTime) {
var startTime = new Date();
$("[class*=bfasg] .radio, #movenextbtn").click(function () {
var endTime = new Date();
if ((endTime - startTime) / 1000 <= minTime) {
alert('You must spend at least ' + minTime + ' seconds on the question.');
return false;
}
});
}
});
(By the way, returning true from a jQuery event handler has no meaning, so I've removed it above.)
Below you've commented:
What happens is that I want clicking the radio button to automatically trigger the "Next" button for going to the next page since I have one question per page.
That doesn't fundamentally change things. You haven't shown what the button does to move to the next page, but you'd just put that code in the one click handler above. E.g., you still hook click on both the radio buttons and the button, and you still handle that event using common code. E.g.:
$(document).ready(function () {
minTime(1.5);
function minTime(minTime) {
var startTime = new Date();
$("[class*=bfasg] .radio, #movenextbtn").click(function () {
var endTime = new Date();
if ((endTime - startTime) / 1000 <= minTime) {
alert('You must spend at least ' + minTime + ' seconds on the question.');
return false;
} else {
// ****Move to next page here****
}
});
}
});
Alternately, you could have the radio button click trigger a click event on the button, like this:
$(document).ready(function () {
minTime(1.5);
function minTime(minTime) {
var startTime = new Date();
// Hook up `click` on the radio buttons
$("[class*=bfasg] .radio").click(function () {
// Respond to click by firing click on the #movenextbtn
$("#movenextbtn").click();
});
// Hook up `click` on the #movenextbtn
$("#movenextbtn").click(function () {
var endTime = new Date();
if ((endTime - startTime) / 1000 <= minTime) {
alert('You must spend at least ' + minTime + ' seconds on the question.');
return false;
}
});
}
});
I'm not a huge fan of firing synthetic events like that when you could use common logic, but it's an option.

function callMe() {
// Do Something
}
$(document).ready(function() {
callMe();
});
DECLARE FUNCTION outside of ready(), but then define FUNCTION inside of ready().it's better to define them outside of document ready. And, if you need to, place the implementation of the method within the document ready.

Related

"Snooze"-like function in Javascript to trigger event at a later time

This question might already been discussed but I couldn't find quite what I was looking for.
I'm working on Adobe Edge Animate with HTML+JS. This is a full JS question so that's why I'm posting it here. I wrote a bit of code to have dialogue box appear at a specific time during the day. The dialogue has two buttons: "Play Video Now" and "Remind me in 10 mins"
Here is the code:
function updateClock() {
var d = new Date(); // current date
var m = d.getMinutes();
var h = d.getHours();
console.log(h, ":", m);
// call this function again in 1000ms
sym.updateClock = setTimeout(updateClock, 1000);
if (h == 9 && m == 0) { //at 9hrs 00 min
//run the dialogue for the morning pause
sym.play(1000);
} else {
sym.stop(1000);
}
}
updateClock(); // initial call
Then I have to bind the snooze button so it adds 10 minutes to my conditional statement. I know I have to add some sort of "count" variable, but I don't know exactly how to do it.
(function(symbolName) {
Symbol.bindElementAction(compId, symbolName, "${_snoze_btn}", "click", function(sym, e) {
}
pretty sure you just want this -
(function(symbolName) {
Symbol.bindElementAction(compId, symbolName, "${_snoze_btn}", "click", function(sym, e) {
// remind again again in 10 minutes
popupPlayOrSnoozeDialogTimer = setTimeout(popupPlayOrSnoozeDialogTimer, 600000);
});
}())
If you want to add 10 minutes to the current timeout until that function is called again, check out this answer or look at new Date().valueOf()

Overlay div doesn't prevent the next event that fired in a specific time window

In my application, I add a loaderDiv to avoid all userevents on the page.
The loader appears. If the user force a clickevent(eg. greenContainer onclick) the event is fired after the loader div disappears.
I've created a short example the show you the problem
js:
function appendOverlay(){
var maskDiv = $('<div id="overlay" class="loadmask" onclick:"return false;"><div class="removeDiv" onclick="sleep(3000)"><span>click to remove overlay after 3 seconds</span></div></div>');
$('body').append(maskDiv);
}
function removeDiv(){
$("#overlay").remove();
}
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
removeDiv();
}
Demo
How can I solve this problem?
Solved this problem by using setTimeout(removeDiv(),0).
This is a problem with the event loop execution in Javascript.
Propergate the removeDiv() to the next tick and the userEvent onClick() is execute first.
Why is setTimeout(fn, 0) sometimes useful?
The JavaScript Event Loop
Strange 'sleep' function there.
Why don't u use the internal timeout :
function sleep(milliseconds) {
setTimeout(function() {
removeDiv();
}, milliseconds);
}
DEMO

Prevent link event after mousdown down delay

I'm working on a function so that when an user clicks and holds onto a link, the link does not send the user to the appropriate link. However, the function that I used is not working. What I want is for the user to click on a link and if they hold it down for longer than one second, the link no longer works and no event is fired. After looking through it sometime, I can't find what's wrong with the code. So my question is, what did I do wrong? http://jsfiddle.net/rQP6g/2/
<a href="www.google.com" >link</a>
<script>
var timeoutId = 0;
$('a').mouseup(function() {
timeoutId = setTimeout(function(e) {
e.preventDefault();
e.stopPropagation();
}, 1000);
}).bind('mouseup', function() {
clearTimeout(timeoutId);
});
</script>
This should work: http://jsfiddle.net/rQP6g/18/
The JS looks as follows:
var mousedownTime;
$('a').mousedown(function(e) {
mousedownTime = new Date();
}).click(function(e) {
// If the mouse has been hold down for more than 1000 milliseconds ( 1 sec. ), cancel the click
if(Math.abs(new Date() - mousedownTime) > 1000)
e.preventDefault();
});​
The basic idea is to capture the time when the mouse button is pressed down - then, when released, the click event is fired and it is computed if more than 1 sec. has elapsed since the link was pressed. If this is the case, the click event is cancelled and the link won't load :)
Here is your answer: http://jsfiddle.net/rQP6g/19/ tested and working
Also your jQuery code:
var startingTime, timeOut = 1000;
(function($) {
$('a').bind('click', function(e) {
e.preventDefault();
}).bind('mousedown', function(e) {
window.startingTime = +new Date();
}).bind('mouseup', function (e) {
console.log('Starting time: '+ window.startingTime);
var currentTime = +new Date();
console.log('Current time: '+ (+new Date()));
var difference = currentTime - window.startingTime;
console.log (difference);
if (difference > timeOut) {
console.log('You are too slow, nothing happens');
} else {
console.log($(this).attr('href'));
window.location.href = $(this).attr('href');
}
});
})(jQuery);
I would go with a reverse approach - prevent everything, then allow clicks released before a threshold:
// set threshold in millisecs:
var threshold = 1000;
$('a').on('click',function(event){
event.preventDefault();
// inject current time in link element:
$(this).attr('data-timestamp', new Date.getTime());
}, function(event){
// check mousedown timestamp against mouseup timestamp:
if( (new Date.getTime() - $(this).attr('data-timestamp') < threshold){
window.location.href = $(this).attr('href');
}
});​​​​

How can i do button on hold for two second call function1 if less then two second call function2?

I have this button which is not working correctly for hold button for a period (but it works like click only).
Where i was trying to do if the button is hold for greater/equal then 2 seconds then callfunction1, if the button was pressed less then 2 seconds then callfuntion2.
var clickDisabled = false;
function clickLocker() {
/* #Button: 2 seconds */
clickDisabled = true;
setTimeout(function(){clickDisabled = false;}, 2000);
}
function callfunction1() { // you have hold he button for greater then or equal 2 second }
function callfunction2() { // you have hold the button less then 2 second }
$('.button').live("click",function()
{
if (clickDisabled) {
alert("locked for 2 second");
return;
}
clickLocker();
});
I think this solution should work. I have not tested it but it should give you the right idea.
var startTime;
function callfunction1() { // you have hold he button for greater then or equal 2 second }
function callfunction2() { // you have hold the button less then 2 second }
function buttonDownEvent() {
var Time = new Date();
startTime = Time.getTime();
}
function buttonUpEvent() {
if(new Date().getTime() - startTime < 2000)
callfunction2()
else
callfunction1()
}
$('.button').live("mousedown",function()
{
buttonDownEvent();
});
$('.button').live("mouseup",function()
{
buttonUpEvent();
});
Listen for both events, mousedown and mouseup, measuring the time between both:
var timeDown;
var timeUp;
$('.button').live("mousedown",function(){
timeDown = event.timeStamp;
});
$('.button').live("mouseup",function(){
timeUp = event.timeStamp;
time = timeUp-timeDown;
if (time>2000){
function1();
}else{
function2();
}
});
please note that event.timeStamp wont work well in firefox. For firefox you can do (new Date).getTime();
You can do this using events to the mouseup and mousedown events and timing the difference between them. Also, you need to remember which element caused the click - if the user released the mouse on a different element then it should just do the "non 2-second hold" function. A JSFiddle showing this working is available here: http://jsfiddle.net/35rw3/6/.
That was a great suggestion from slash. This is how you can do this
var clickstart;
var clickstop;
$("a").on('mousedown', function(e) {
clickstart = e.timeStamp;
}).on('mouseup', function(e) {
clickstop = e.timeStamp- clickstart
if(clickstop >= 2000) two()
else one();
});
Demo
Updates:
It might be necessary to track the mouse movement like #MarkRhodes wrote in his comments. So for that, check this update

Impose a wait between two submits

I have a form which does an AJAX action when submitting. Just after a user has submitted the form, I'd like to impose a minimal waiting time of 5sec to post one more time.
What the better way ? I made this script (doesn't work but I guess idea is here):
$("form#submit_under_wall"+array[1]).submit(function() {
var submit_timestamp=0;
var c = new Date();
var now = ISODateString(c);
if(now-submit_timestamp>5){
var d = new Date();
var timestamp_message = ISODateString(d);
submit_timestamp = timestamp_message ;
//AJAX ACTION
}else{ alert("Wait 5sec between each post."); }
return false;
});
This doesnt work because the timestamp is reset every time they submit, you need to move submit_timestamp outside of the function. Also, that 5 should probably be 5 * 1000
something like this (not tested):
var submitTime = (new Date()).getTime() - 5000; //let user submit if he clicks within 5s of page load
$("form#submit_under_wall"+array[1]).submit(function(e) {
var now = (new Date()).getTime();
if(now-submitTime > 5000){
submitTime = (new Date()).getTime();
//AJAX ACTION
} else {
alert("Wait 5sec between each post.");
}
e.preventDefault();
});
The easiest and most standard way would be to use Javascript native setTimeout method.
var last_action;
function ajax_action() {
last_action = Date.getTime();
// AJAX STUFF
}
$("form#submit_under_wall"+array[1]).submit(function(e) {
e.preventDefault(); // Sexier than 'return false'
if(last_action != undefined) {
setTimeout(ajax_action, Date.getTime()-last_action); // Wait for 5s before doing the action
} else {
ajax_action();
}
});
use window.setTimeout()
Wrap what you want to do in a function (eg function foo (){ alert('test'); })
Call it with a 5 second delay setTimeout(foo,5000)

Categories