Preventing a callback from executing until input stops - javascript

A timer to fire an AJAX call if no key is pressed. If a key is pressed, then abort the last timer and add a new timer. That is what I want to do but failed to success. Here is my code:
var t;
input.onkeyup = function(){
$('.confirmText').html('Checking...');
var timeStampObj = new Date()
var timeStamp = timeStampObj.getTime();
var oldTimeStamp = $(this).attr('timeStamp');//I store a timeStamp in the element
if(timeStamp < 500 + oldTimeStamp){
$(this).attr('timeStamp', timeStamp);
clearTimeout(t);
}
t = setTimeout(function(){
$.ajax({
url: 'serverScripts/settings/checkEmailAvailability.php',
data: 'email='+email,
success: function(text){
if(text == 'available'){
$('.confirmText').html('Available!');
}else{
$('.confirmText').html('Occupied!');
}
}
});
}, 500);//Half a second
$(this).attr('timeStamp', timeStamp);
}

It sounds like you're asking for a debouncer. The term comes from electronics. It's a way to prevent multiple events from firing within some time threshold. You can use the following function to create a new function that will only be called if a given amount of time has passed since the last event.
function debounce(callback, timeout, _this) {
var timer;
return function(e) {
var _that = this;
if (timer)
clearTimeout(timer);
timer = setTimeout(function() {
callback.call(_this || _that, e);
}, timeout);
}
}
// requires jQuery
$("div").click(debounce(function() {
console.log("tset");
}, 2000));
The callback given to debounce won't execute as long as click events keep firing.
The excellent Underscore.js library includes an equivalent function and there are at least a couple jQuery plugins:
http://code.google.com/p/jquery-debounce/
http://benalman.com/code/projects/jquery-dotimeout/examples/debouncing/

Where do you define the email variable in your JavaScript?
You need to define email somewhere and then check to see if your script works.
var email = $(this).value; // Pseudo-code - are you using jQuery?

Related

How to expire session if a have a setinterval js running?

I've a page with a chart on it, the chart is update via JS using a setinterval of 20 seconds, now my session is not expiring, i've searched over the internet and didn't found something like this, how i would detect user inactivity with this chart running?
setInterval(function(){
$.ajax({
type:'POST',
url: 'php/grafico.php',
success: function(e){
e = JSON.parse(e);
var linhas = e['linhas'];
var label = new Array();
for(var i = 1;i <= linhas; i++){
label.push('');
}
var preco = new Array();
for(var i = 1;i <= linhas; i++){
preco.push(e[i]['preco']);
}
addData(chartGraph, preco, 0, label);
}
});
var base = $('#Layer_base').height();
$('#menuzinhu').css('min-height',base+'px');
}, 20000);
heres the setinterval function, how it will update the session so it will never expire, but i need it to expire.
Thanks in adv.
You could create a timeout, which is set to fire, the value of the time being how long you should wait for user input/events before deeming them inactive. You'd then reset the timeout whenever an event is triggered by the user, where you define what events signify user activity.
See below for an example, this is untested, but should see you on the right track.
var inactiveTime = 30000; //30 seconds
var interactionEvents = [
"onload",
"onmousemove",
"onmousedown",
"ontouchstart",
"onclick",
"onscroll",
"onkeypress"
];
var timeoutId = null;
var finished = function () {
//You'd put your logic in here to clear the session.
//This gets fired when the user is deemed inactive.
console.log("User inactive.");
};
//Keep track of if the timer has finished, handy if the user stays on
//the page when this has finished, as you can compare it's value to
//detirmine if you should keep running the timeout.
var hasFinished = false;
var reset = function () {
if (hasFinished === true) {
return;
}
//Clear any already running timeout
clearTimeout(timeoutId);
//Start the new timeout
timeoutId = setTimeout(function () {
hasFinished = true;
if (typeof(finished) === "function") {
finished();
}
}, inactiveTime);
//If events reset the timer, apply them
//Attach events which will reset the timer
for (var i = 0, max = interactionEvents.length; i < max; i++) {
document[interactionEvents[i]] = reset();
}
};
//Start the timer with this
reset();
Something like that!

Reset timeout on event with RxJS

I'm experimenting with RxJS (with the JQuery extension) and I'm trying to solve the following use case:
Given that I have two buttons (A & B) I'd like to print a message if a certain "secret combination" is clicked within a given timeframe. For example the "secret combination" could be to click "ABBABA" within 5 seconds. If the combination is not entered within 5 seconds a timeout message should be displayed. This is what I currently have:
var secretCombination = "ABBABA";
var buttonA = $("#button-a").clickAsObservable().map(function () { return "A"; });
var buttonB = $("#button-b").clickAsObservable().map(function () { return "B"; });
var bothButtons = Rx.Observable.merge(buttonA, buttonB);
var outputDiv = $("#output");
bothButtons.do(function (buttonName) {
outputDiv.append(buttonName);
}).bufferWithTimeOrCount(5000, 6).map(function (combination) {
return combination.reduce(function (combination, buttonName) {
return combination + buttonName;
}, "");
}).map(function (combination) {
return combination === secretCombination;
}).subscribe(function (successfulCombination) {
if (successfulCombination) {
outputDiv.html("Combination unlocked!");
} else {
outputDiv.html("You're not fast enough, try again!");
}
});
While this works fairly well it's not exactly what I want. I need the bufferWithTimeOrCount to be reset when button A is pressed for the first time in a new timeframe. What I'm looking for is that as soon as the secret combination is pressed (ABBABA) I'd like "Combination unlocked!" to be shown (I don't want to wait for the time window to be expired).
Throttle is the typical operator for the delaying with reactive resetting effect you want.
Here's how you can use throttle in combination with scan to gather the combination inputted before the 5 seconds of silence:
var evaluationStream = bothButtons
.merge(bothButtons.throttle(5000).map(function(){return "reset";})) // (2) and (3)
.scan(function(acc, x) { // (1)
if (x === "reset") return "";
var newAcc = acc + x;
if (newAcc.length > secretCombination.length) {
return newAcc.substr(newAcc.length - secretCombination.length);
}
else {
return newAcc;
}
})
.map(function(combination) {
return combination === secretCombination;
});
var wrongStream = evaluationStream
.throttle(5000)
.filter(function(result) { return result === false; });
var correctStream = evaluationStream
.filter(function(result) { return result === true; });
wrongStream.subscribe(function() {
outputDiv.html("Too slow or wrong!");
});
correctStream.subscribe(function() {
outputDiv.html("Combination unlocked!");
});
(1) We scan to concatenate the input characters. (2) Throttle waits for 5 seconds of event silence and emits the last event before that silence. In other words, it's similar to delay, except it resets the inner timer when a new event is seen on the source Observable. We need to reset the scan's concatenation (1), so we just map the same throttled Observable to "reset" flags (3), which the scan will interpret as clearing the accumulator (acc).
And here's a JSFiddle.

setTimeout/Interval called from within $.each method?

I am a little confused, I have read from other places that timeout/interval is the best way to make a function in Javascript run every x seconds. I have to make it so that my function runs every 1 second, as this is a rule for the API I'm using.
My code is as follows:
$.each(match_details_json.result.players, function(index, v){
if (v.account_id == 38440257){ //finds desired playerid
var match_id_2 = matches[i];
hero = v.hero_id;
playerpos = v.player_slot;
var kills = v.kills;
var deaths = v.deaths;
var assists = v.assists;
var kda = ""+kills+"/"+deaths+"/"+assists+"";
console.log(match_id_2, hero, playerpos, result, gamemode, kda);
callback();
console.log(match_id_2, hero, result, gamemode, kda);
h=h+1;
setTimeout(get_match_details(h), 10000);
i=i+1;
}
else{
console.log('Not desired player, skipping...');
}
});
Lots of messy code there. But the important part is setTimeout(get_match_details(h), 10000);
Whether that is correct or not, that's me trying to say "Run this function again in 10 seconds" and to continue that, until the each method is finished. It doesn't work.
If necessary, here is my get_match_details function:
function get_match_details(){
$.ajax({
url: 'php/ApiMatchPull.php',
data: {accountid:'38440257', querytype:'GetMatchDetails', querycondition1:'match_id='+matches[h]},
success: function (data) {
console.log ('Match Details were was pulled successfully');
match_details_json = data;
matchdetailsfill(checkvalidity);
}
});
}
Thank you in advance.
This is precisely what setInterval & clearInterval are for.
So instead of setTimeout, you could use it something like :
var timer = setInterval(function() {
get_match_details(h);
}, 1000); // for every second
And when you want to stop it, use:
clearInterval(timer);
You execute the function get_match_details immedatiately, change your code to
setTimeout( function() {
get_match_details(h)
}, 10000 );
What happens in your code is that you loop through all your players and after 10 seconds as many Ajax calls (get_match_details) will be made at the same time.
If you want to have 10 seconds intervals between each ajax call you have to refactor your approach to something like this:
var l = [1,2,3,4,5];
var c = l.length;
var ix = -1;
ajax = function( n ) {
alert( 'do some ajax with ' + n )
}
call = function() {
if( c > ++ix ) {
ajax( l[ ix ] );
setTimeout( function() { call(); }, 1000 );
}
}
call();

Javascript clearInterval() not able to clear the interval

get_user_record() this function call the method which is pulling data in database. I used time-out because I don’t want response from this method, showUpdatedProgressBar() method which is continuously checking database count and accordingly giving value to progress bar. For that purpose I used setInterval() function which is working but I was not able to clear the interval. Please suggest me where I go wrong.
function get_user_record(){
$.ajax({
url:"/GetData",
type: "GET",
timeout: 2000,
success:function(result){
//alert('success');
},
error: function(xhr, status, err){
//alert('Connection Error. Please try again.')
}
});
var timer = 0;
showUpdatedProgressBar(timer);
}
}
function showUpdatedProgressBar(timer){
$.ajax({
url:"/get_updated_data",
type: "GET",
success:function(result){
result = result.split(',');
var obj = {totalRecords: result[0], recordsTaken: result[1]};
var bar_value = obj.recordsTaken/obj.totalRecords * 100;
$( "#progressbar" ).progressbar({ value: bar_value });
if(obj.recordsTaken == obj.totalRecords ){
clearInterval(timer);
}
else
{
timer = setInterval(function(){ showUpdatedProgressBar(timer) },1000);
}
}
});
}
Previously I defined var timer locally and set to 0
Now it works just by defining var timer; globally and not setting it to zero
timer = setInterval(function(){ showUpdatedProgressBar(timer) },1000);
'timer' is assigned a new interval id with every recursive iteration (it is overwritten). Therefore only the last generated id will be used in clearInterval.

Need to delay javascript execution, but setTimeout is proving problematic

Thank you for taking the time to help me.
I am writing a game where an animated train icon moves along a given path to a destination, pausing at waypoints along the way. This is intended to give the impression of animation.
The game is coded in Facebook Javascript. I need to find a way to make the train icon pause for 1 second before moving on to the next waypoint. I hoped to find a function that would allow me to pause script execution for one second, but nothing like that seems to exist in JS. So I tried setTimeout, but my primary problem with this is twofold:
I need to pass an array into the callback function as an argument, and I can't figure out how to make setTimeout do this.
I finally succeeded in using setTimeout to execute my train animation code for 5 waypoints (I overcame the issue in 1 by using global variables). Unfortunately, it appears that all five calls to setTimeout got queued almost simultaneously, which resulted in waiting one second for the first setTimeout to fire, thenn they all fired at once ruining the illusion of train animation.
I've been battling this problem for six hours straight. It would be wonderful if someone could help me find a solution. Thanks!
Here's the code:
function myEventMoveTrainManual(evt, performErrorCheck) {
if(mutexMoveTrainManual == 'CONTINUE') {
var ajax = new Ajax();
var param = {};
if(evt) {
var cityId = evt.target.getParentNode().getId();
var param = { "city_id": cityId };
}
ajax.responseType = Ajax.JSON;
ajax.ondone = function(data) {
var actionPrompt = document.getElementById('action-prompt');
actionPrompt.setInnerXHTML('<span><div id="action-text">'+
'Train en route to final destination...</div></span>');
for(var i = 0; i < data.length; i++) {
statusFinalDest = data[i]['status_final_dest'];
//pause(1000);
gData = data[i];
setTimeout(function(){drawTrackTimeout()},1000);
if(data[i]['code'] == 'UNLOAD_CARGO' && statusFinalDest == 'ARRIVED') {
unloadCargo();
} else if (data[i]['code'] == 'MOVE_TRAIN_AUTO' || data[i]['code'] == 'TURN_END') {
//moveTrainAuto();
} else {
// handle error
}
mutexMoveTrainManual = 'CONTINUE';
}
}
ajax.post(baseURL + '/turn/move-train-final-dest', param);
}
}
function drawTrackTimeout() {
var trains = [];
trains[0] = gData['train'];
removeTrain(trains);
drawTrack(gData['y1'], gData['x1'], gData['y2'], gData['x2'], '#FF0', trains);
gData = null;
}
Typically this would be done by creating an object (say called myTrain) that has all its own data and methods, then call a myTrain.run mehod that looks to see where the train is. If it's between two stations, it calls itself with setTimeout and say a 50ms delay. When it reaches a station, it calls itself in 1000ms, creating a 1 second pause at the station.
If you queue the setTimeouts all at once, you run the risk of them all being delayed by some other process, then all running at once.
Hey, bit of fun (careful of wrapping). Needed a bit of practice with good 'ole prototype inheritance:
<!-- All the style stuff should be in a rule -->
<div style="position: relative; border: 1px solid blue;">
<div id="redTrain"
style="width:10px;height:10px;background-color:red; position:absolute;top:0px;left:0px;"></div>
</div>
<script type="text/javascript">
// Train constructor
function Train(id) {
this.element = document.getElementById(id);
this.timerId;
}
// Methods
// Trivial getPos function
Train.prototype.getPos = function() {
return this.element.style.left;
}
// Trivial setPos function
Train.prototype.setPos = function(px) {
this.element.style.left = parseInt(px,10) + 'px';
}
// Move it px pixels to the right
Train.prototype.move = function(px) {
this.setPos(px + parseInt(this.getPos(),10));
}
// Recursive function using setTimeout for animation
// Probably should accept a parameter for lag, long lag
// should be a multiple of lag
Train.prototype.run = function() {
// If already running, stop it
// so can interrupt a pause with a start
this.stop();
// Move the train
this.move(5);
// Keep a reference to the train for setTimeout
var train = this;
// Default between each move is 50ms
var lag = 50;
// Pause for 1 second each 100px
if (!(parseInt(this.getPos(),10) % 100)) {
lag = 1000;
}
train.timerId = window.setTimeout( function(){train.run();}, lag);
}
// Start should do a lot more initialising
Train.prototype.start = function() {
this.run();
}
// Stops the train until started again
Train.prototype.stop = function() {
if (this.timerId) {
clearTimeout(this.timerId);
}
}
// Set back to zero
Train.prototype.reset = function() {
this.stop();
this.setPos(0);
}
// Initialise train here
var myTrain = new Train('redTrain');
</script>
<p> </p>
<button onclick="myTrain.start();">Start the train</button>
<button onclick="myTrain.stop();">Stop the train</button>
<button onclick="myTrain.reset();">Reset the train</button>
To pass arguments, this might help you:
setTimeout(function() {
(function(arg1, arg2) {
// you can use arg1 / arg2 here
})('something', 123);
}, 1000);
Or, if you use a defined function:
setTimeout(function() {
someFunction('something', 123);
}, 1000);
It basically starts a timeout; after one second the function is invoked with the specified arguments.
How about using OO principles to simplify the problem? Create an "object" Train which has the following methods:
//train obj
function Train(){
this.isOnWaypoint = function(){
return calculateIsWayPoint()
}
}
//main logic
var train = new Train()
var doneWaiting = false
var doneWaitingTimeout = undefined
var gameLoop = setInterval(1000,function(){
...
if(train.isOnWaypoint() && !doneWaiting){
if(doneWaitingTimeout == undefined){
setTimeOut(5000,function(){
doneWaiting = true
doneWaitingTimeout = undefined
})
}
}
...
})
Here's the solution I finally came up with:
function drawTrackTimeout() {
if(gData != null && gIndex < gData.length) {
var trains = [];
trains[0] = gData[gIndex]['train'];
removeTrain(trains);
drawTrack(gData[gIndex]['y1'], gData[gIndex]['x1'], gData[gIndex]['y2'], gData[gIndex]['x2'], '#FF0', trains);
statusFinalDest = gData[gIndex]['status_final_dest'];
if(statusFinalDest == 'ARRIVED') {
unloadCargo();
} else if (gData[gIndex]['code'] == 'MOVE_TRAIN_AUTO' || gData[gIndex]['code'] == 'TURN_END') {
//moveTrainAuto();
} else {
// handle error
}
gIndex++;
} else {
clearInterval(gIntid);
gIntid = null;
gData = null;
gIndex = 0;
}
}
function myEventMoveTrainManual(evt, performErrorCheck) {
//debugger;
if(mutexMoveTrainManual == 'CONTINUE') {
var ajax = new Ajax();
var param = {};
if(evt) {
var cityId = evt.target.getParentNode().getId();
var param = { "city_id": cityId };
}
ajax.responseType = Ajax.JSON;
ajax.ondone = function(data) {
var actionPrompt = document.getElementById('action-prompt');
actionPrompt.setInnerXHTML('<span><div id="action-text">'+
'Train en route to final destination...</div></span>');
gData = data;
gIndex = 0;
gIntid = setInterval(function(){drawTrackTimeout()},1000);
}
ajax.post(baseURL + '/turn/move-train-final-dest', param);
}
}

Categories

Resources