How to reset and set up timer function? - javascript

I have a quiz app with a controller where I should set up a timer that should be counting for 30s, and then stop the quiz if there is no activity in that time. If there is some activity in the meantime it should be reset and start counting again. I have set up web socket listeners for that. How should I do the timer setup?
This is my controller:
angular.module('quiz.controllers')
.controller('MultiPlayerQuestionController', function(
$scope,
$rootScope,
$state,
$stateParams,
$timeout,
UserService,
QuizService,
InviteService,
MessageService,
SocketService
) {
$scope.user = UserService.get();
$scope.quiz = QuizService.getCurrent();
$scope.opponent = $scope.user.player.id == $scope.quiz.players[0].id
? $scope.quiz.players[1]
: $scope.quiz.players[0]
|| null;
$scope.currentQuestion = {};
$scope.answer = {};
$scope.showAlternatives = false;
$scope.showCorrect = false;
$scope.isLast = false;
$scope.opponentAnswered = false;
var timeouts = {
stop: null,
activate: null
};
var startTime,
loadBar,
initiated = false;
// Opponent has answered; update score display
SocketService.socket.removeAllListeners('gameEvent:opponentAnswer');
SocketService.socket.on('gameEvent:opponentAnswer', function(message) {
$scope.opponentAnswered = true;
QuizService.updateOpponentScore(message.data.totalScore);
});
// Next question is triggered from all players having answered
SocketService.socket.removeAllListeners('gameEvent:nextQuestion');
SocketService.socket.on('gameEvent:nextQuestion', function(message) {
$timeout(function() {
QuizService.setCurrentQuestion(message.data.question);
setupQuestion(message.data.question);
}, 3000);
});
// Game is finished, go to score screen
SocketService.socket.removeAllListeners('gameEvent:quizFinished');
SocketService.socket.on('gameEvent:quizFinished', function(message) {
stopQuiz();
$timeout(function() {
$state.go('multiplayer.score');
}, 3000);
});
// An opponent has quit, go to score screen
SocketService.socket.removeAllListeners('gameEvent:opponentQuit');
SocketService.socket.on('gameEvent:opponentQuit', function(message) {
stopQuiz();
MessageService.alertMessage('Motstanderen din har enten gitt opp eller blitt frakoblet.');
$state.go('multiplayer.score');
});
// Disconnected. Go back to home screen.
SocketService.socket.removeAllListeners('reconnecting');
SocketService.socket.on('reconnecting', function() {
MessageService.alertMessage('Du har mistet tilkoblingen. Spillet har blitt avbrutt.');
SocketService.socket.removeAllListeners('reconnecting');
$state.go('main.front');
});
// The app was paused (closed), equals giving up.
var pauseEvent = $rootScope.$on('app:paused', function() {
QuizService.giveUpCurrent($scope.user.player);
var resumeEvent = $rootScope.$on('app:resumed', function() {
stopQuiz();
$state.go('multiplayer.score');
resumeEvent();
});
pauseEvent();
});
/**
* Give up the current quiz.
*/
$scope.giveUp = function (player) {
MessageService.confirm('Ønsker du å avbryte quizen?').then(function(result) {
if (result) {
QuizService.giveUpCurrent(player);
$state.go('multiplayer.score', {}, { reload: true });
stopQuiz();
}
});
};
/**
* Go to next question for current quiz.
*/
$scope.nextQuestion = function() {
$timeout.cancel(timeouts.stop);
$timeout.cancel(timeouts.activate);
QuizService.nextQuestion().$promise.then(function(question) {
setupQuestion(QuizService.getCurrentQuestion());
});
};
/**
* Finish quiz.
*/
$scope.finish = function() {
QuizService.finish();
$state.go('multiplayer.score');
};
/**
* Choose an alternative (aka answer current question).
*/
$scope.chooseAlternative = function(alternative) {
if (!$scope.showAlternatives || $scope.showCorrect) {
return;
}
var answerTime = Date.now() - startTime;
$scope.answer = alternative;
QuizService.answer(alternative, answerTime);
if (timeouts.stop) {
$timeout.cancel(timeouts.stop);
}
stopQuestion();
};
/**
* Set up a new question - change data and start countdown to activate question.
*/
var setupQuestion = function(question) {
$scope.showAlternatives = false;
$scope.showCorrect = false;
$scope.currentQuestion = question;
$scope.answer = {};
$scope.isLast = parseInt($scope.quiz.questionCount) == parseInt($scope.currentQuestion.questionNumber);
var prepareTime = 5000;
var newLoadBar = loadBar.cloneNode(true);
loadBar.parentNode.replaceChild(newLoadBar, loadBar);
loadBar = newLoadBar;
setAnimationDuration(loadBar, 'loadbar', prepareTime);
timeouts.activate = $timeout(activateQuestion, prepareTime);
};
/**
* A question timed out; stop and send empty answer.
*/
var questionTimeout = function() {
// Delay answering by a random delay between 0 and 500ms.
$timeout(function() {
stopQuestion();
QuizService.noAnswer($scope.currentQuestion.id);
}, Math.floor((Math.random() * 500) + 1));
};
/**
* Activate the current question: show alternatives and open answering.
*/
var activateQuestion = function() {
$scope.showAlternatives = true;
var timeToAnswer = 10000;
startTime = Date.now();
var newLoadBar = loadBar.cloneNode(true);
loadBar.parentNode.replaceChild(newLoadBar, loadBar);
loadBar = newLoadBar;
setAnimationDuration(newLoadBar, 'loadbar', timeToAnswer);
timeouts.stop = $timeout(questionTimeout, timeToAnswer);
};
/**
* Stop the current question and show the correct answer info.
*/
var stopQuestion = function() {
$scope.showCorrect = true;
stopAnimation(loadBar);
$timeout.cancel(timeouts.stop);
};
/**
* End the current quiz.
*/
var stopQuiz = function() {
SocketService.socket.removeAllListeners('gameEvent:opponentAnswer');
SocketService.socket.removeAllListeners('gameEvent:nextQuestion');
SocketService.socket.removeAllListeners('gameEvent:quizFinished');
SocketService.socket.removeAllListeners('gameEvent:opponentQuit');
SocketService.socket.removeAllListeners('reconnecting');
$timeout.cancel(timeouts.stop);
$timeout.cancel(timeouts.activate);
};
/**
* Set the animation duration for an element. Used to stop and start the
* progress bar.
*/
var setAnimationDuration = function(element, keyframes, duration) {
var animationSetting = keyframes + ' ' + duration + 'ms linear';
element.style.webkitAnimation = animationSetting;
element.style.animation = animationSetting;
}
var stopAnimation = function(element) {
element.style.webkitAnimation = 'none';
element.style.animation = 'none';
};
if (!initiated) {
initiated = true;
loadBar = document.getElementById('load-bar');
setupQuestion(QuizService.getCurrentQuestion());
}
});
I have tried with calling the responseTimer function that I have made in my controller. At the begging of the file I am calling it like this:
responseTimer(30000);
And then later I am defining it like this:
var responseTimer = function (time) {
responseTimer = $timeout(stopQuiz, time);
console.log('Started timer');
};
var resetResponseTimer = function () {
$timeout.cancel(responseTimer);
responseTimer(30000);
console.log("Timer reset");
};
But I get an error:
TypeError: responseTimer is not a function

problem comes from a scope conflict. In your code
// responseTimer is declared as a global function
var responseTimer = function (time) {
// as the var keyword is not specify, scope of responseTimer becomes global and not local and overrides the previous declaration
responseTimer = $timeout(stopQuiz, time);
That is why you get the error
responseTimer is not a function
To solve the problem add the var keyword before the second declaration and name your variables appropriately. A good practice is to add an action verb when naming function/object's methods, in your case triggerResponseTimer as name of your function and responseTimer as name of the variable so final porposition would be:
var triggerResponseTimer = function (time) {
var responseTimer = $timeout(stopQuiz, time);

You should better use $intervall:
Here you will find a good sample:
http://tutorials.jenkov.com/angularjs/timeout-interval.html
Also good sample:
https://docs.angularjs.org/api/ng/service/$interval

Related

JavaScript + jQuery + Angular: Element is not found

I have a JavaScript function defined. Inside this function, I define variables of type jQuery elements. So, the variables refer to divs on the HTML. This function returns an object that has a single function init().
In the $(document).ready function, I call init() function.
The problem is when the script loads, the DOM is not ready and hence the variables referring to jQuery items are being set to undefined.
Later, I call the init() function inside Angular ngOnInit() to make sure things are well initialized, so nothing is happening as the variables above are undefined and they are not being re-calculated again.
Seems, when a function in JavaScript is defined, its body runs, and hence the variables are run and set to undefined as the HTML elements were not in the DOM yet.
How can I re-calculate the variables when init() runs? I cannot get my mind on this thing.
Thanks
var mQuickSidebar = function() {
var topbarAside = $('#m_quick_sidebar');
console.log('Function: ', Date.now());
var topbarAsideTabs = $('#m_quick_sidebar_tabs');
var topbarAsideClose = $('#m_quick_sidebar_close');
var topbarAsideToggle = $('#m_quick_sidebar_toggle');
var topbarAsideContent = topbarAside.find('.m-quick-sidebar__content');
var initMessages = function() {
var messenger = $('#m_quick_sidebar_tabs_messenger');
if (messenger.length === 0) {
return;
}
var messengerMessages = messenger.find('.m-messenger__messages');
var init = function() {
var height = topbarAside.outerHeight(true) -
topbarAsideTabs.outerHeight(true) -
messenger.find('.m-messenger__form').outerHeight(true) - 120;
// init messages scrollable content
messengerMessages.css('height', height);
mApp.initScroller(messengerMessages, {});
}
init();
// reinit on window resize
mUtil.addResizeHandler(init);
}
var initSettings = function() {
var settings = $('#m_quick_sidebar_tabs_settings');
if (settings.length === 0) {
return;
}
// init dropdown tabbable content
var init = function() {
var height = mUtil.getViewPort().height - topbarAsideTabs.outerHeight(true) - 60;
// init settings scrollable content
settings.css('height', height);
mApp.initScroller(settings, {});
}
init();
// reinit on window resize
mUtil.addResizeHandler(init);
}
var initLogs = function() {
// init dropdown tabbable content
var logs = $('#m_quick_sidebar_tabs_logs');
if (logs.length === 0) {
return;
}
var init = function() {
var height = mUtil.getViewPort().height - topbarAsideTabs.outerHeight(true) - 60;
// init settings scrollable content
logs.css('height', height);
mApp.initScroller(logs, {});
}
init();
// reinit on window resize
mUtil.addResizeHandler(init);
}
var initOffcanvasTabs = function() {
initMessages();
initSettings();
initLogs();
}
var initOffcanvas = function() {
topbarAside.mOffcanvas({
class: 'm-quick-sidebar',
overlay: true,
close: topbarAsideClose,
toggle: topbarAsideToggle
});
// run once on first time dropdown shown
topbarAside.mOffcanvas().one('afterShow', function() {
mApp.block(topbarAside);
setTimeout(function() {
mApp.unblock(topbarAside);
topbarAsideContent.removeClass('m--hide');
initOffcanvasTabs();
}, 1000);
});
}
return {
init: function() {
console.log('Inside Init(): ', Date.now());
console.log($('#m_quick_sidebar')); // topbarAside is undefined here!
if (topbarAside.length === 0) {
return;
}
initOffcanvas();
}
}; }();
$(document).ready(function() {
console.log('document.ready: ', Date.now());
mQuickSidebar.init();
});
The problem is that you immediately invoke your function mQuickSidebar not
Seems, when a function in JavaScript is defined, its body runs
var mQuickSidebar = function() {
var topbarAside = $('#m_quick_sidebar');
console.log('Function: ', Date.now());
var topbarAsideTabs = $('#m_quick_sidebar_tabs');
var topbarAsideClose = $('#m_quick_sidebar_close');
var topbarAsideToggle = $('#m_quick_sidebar_toggle');
var topbarAsideContent = topbarAside.find('.m-quick-sidebar__content');
...
}(); // <---- this runs the function immediately
So those var declarations are run and since the DOM is not ready those selectors don't find anything. I'm actually surprised that it does not throw a $ undefined error of some sort
This looks like a broken implementation of The Module Pattern
I re-wrote your code in the Module Pattern. The changes are small. Keep in mind that everything declared inside the IIFE as a var are private and cannot be accessed through mQuickSidebar. Only the init function of mQuickSidebar is public. I did not know what you needed to be public or private. If you need further clarity just ask.
As a Module
var mQuickSidebar = (function(mUtil, mApp, $) {
console.log('Function: ', Date.now());
var topbarAside;
var topbarAsideTabs;
var topbarAsideClose;
var topbarAsideToggle;
var topbarAsideContent;
var initMessages = function() {
var messenger = $('#m_quick_sidebar_tabs_messenger');
if (messenger.length === 0) {
return;
}
var messengerMessages = messenger.find('.m-messenger__messages');
var init = function() {
var height = topbarAside.outerHeight(true) -
topbarAsideTabs.outerHeight(true) -
messenger.find('.m-messenger__form').outerHeight(true) - 120;
// init messages scrollable content
messengerMessages.css('height', height);
mApp.initScroller(messengerMessages, {});
};
init();
// reinit on window resize
mUtil.addResizeHandler(init);
};
var initSettings = function() {
var settings = $('#m_quick_sidebar_tabs_settings');
if (settings.length === 0) {
return;
}
// init dropdown tabbable content
var init = function() {
var height = mUtil.getViewPort().height - topbarAsideTabs.outerHeight(true) - 60;
// init settings scrollable content
settings.css('height', height);
mApp.initScroller(settings, {});
};
init();
// reinit on window resize
mUtil.addResizeHandler(init);
};
var initLogs = function() {
// init dropdown tabbable content
var logs = $('#m_quick_sidebar_tabs_logs');
if (logs.length === 0) {
return;
}
var init = function() {
var height = mUtil.getViewPort().height - topbarAsideTabs.outerHeight(true) - 60;
// init settings scrollable content
logs.css('height', height);
mApp.initScroller(logs, {});
};
init();
// reinit on window resize
mUtil.addResizeHandler(init);
};
var initOffcanvasTabs = function() {
initMessages();
initSettings();
initLogs();
};
var initOffcanvas = function() {
topbarAside.mOffcanvas({
class: 'm-quick-sidebar',
overlay: true,
close: topbarAsideClose,
toggle: topbarAsideToggle
});
// run once on first time dropdown shown
topbarAside.mOffcanvas().one('afterShow', function() {
mApp.block(topbarAside);
setTimeout(function() {
mApp.unblock(topbarAside);
topbarAsideContent.removeClass('m--hide');
initOffcanvasTabs();
}, 1000);
});
};
return {
init: function() {
console.log('Inside Init(): ', Date.now());
console.log($('#m_quick_sidebar')); // topbarAside is undefined here!
topbarAside = $('#m_quick_sidebar');
topbarAsideTabs = $('#m_quick_sidebar_tabs');
topbarAsideClose = $('#m_quick_sidebar_close');
topbarAsideToggle = $('#m_quick_sidebar_toggle');
topbarAsideContent = topbarAside.find('.m-quick-sidebar__content');
if (topbarAside.length === 0) {
return;
}
initOffcanvas();
}
};
})(mUtil, mApp, $);
$(document).ready(function() {
console.log('document.ready: ', Date.now());
mQuickSidebar.init();
});

javascript, setInterval function starts counting not from 0

I have noticed, that my setInterval function starts counting from 1, and sometimes even from 10. But if i increase the interval to some 20 seconds, it starts counting correctly from 0. Subsequent counting is correct - adds one in every step, but the initial cnt value, if i reduce to internval to some 5 seconds, becomes wrong.
var stepProt = function () {
console.log('started stepProt constructor');
this.step = 20; //seconds
this.cnt = 0; //init counter, pointer to rtArr
};
stepProt.prototype.countingFnc = function () {
console.log('started stepFnc.prototype.countingFnc');
var msec = this.step*1000;
var that = this;
that.cnt=0;
this.nameToStop = window.setInterval( function () {
that.stepFnc(); }, msec );
}
stepProt.prototype.stepFnc = function() {
console.log (' 132 startedFnc rtG.prototype.stepFnc, this.cnt='+this.cnt ); //if interval is 5seconds, this.cnt usually starts from 1, but sometimes from 10, instead of starting from 0. All other steps are correct, +1 each time.
/* here there is some logics, which takes time */
this.cnt++;
};
var stepIn = new stepProt(); //instance
stepIn.stepFnc();
What could be the reason and how to resolve?
p.s.
Actually, i use this function before window onload. Maybe this is the reason?
I include many scripts before window.onload.
Later i make single script for window.onload functionality.
I put
var stepIn = new stepFnc(); //instance
stepIn.stepFnc();
before window onload, because if i use it in window.onload, for some reason, other functions does not understand stepIn instance as a global variable accessable everythere. Maybe it is because i use php template.
You should call stepIn.countingFnc(); to start the process. Another thing is that I'd change the name of the function stepFnc so it doesn't match with the constructor name for readability.
var stepFnc = function () {
console.log('started stepFnc constructor');
this.step = 20; //seconds
this.cnt = 0; //init counter, pointer to rtArr
};
stepFnc.prototype.countingFnc = function () {
console.log('started stepFnc.prototype.countingFnc');
var msec = this.step*1000;
var that = this;
that.cnt=0;
this.nameToStop = setInterval( function () {
that.triggerFnc(); }, msec );
}
stepFnc.prototype.triggerFnc = function() {
console.log (' 132 startedFnc rtG.prototype.stepFnc, this.cnt='+this.cnt ); //if interval is 5seconds, this.cnt usually starts from 1, but sometimes from 10, instead of starting from 0. All other steps are correct, +1 each time.
/* here there is some logics, which takes time */
this.cnt++;
};
var stepIn = new stepFnc();
stepIn.countingFnc();
Hope this helps. ;)
var stepFnc = function () {
console.log('started stepFnc constructor');
this.step = 1; //seconds
this.cnt = 0; //init counter, pointer to rtArr
};
stepFnc.prototype.countingFnc = function () {
console.log('started stepFnc.prototype.countingFnc');
var msec = this.step*1000;
var that = this;
that.cnt=0;
this.nameToStop = window.setInterval( function () {
that.stepFnc(); }, msec );
};
stepFnc.prototype.stepFnc = function() {
console.log (' 132 startedFnc rtG.prototype.stepFnc, this.cnt='+this.cnt ); //if interval is 5seconds, this.cnt usually starts from 1, but sometimes from 10, instead of starting from 0. All other steps are correct, +1 each time.
/* here there is some logics, which takes time */
this.cnt++;
};
var stepIn = new stepFnc();
stepIn.countingFnc();
Seems the reason is that i use setInterval in script not in window.onload, thus the first counter is wrong. I created function to check if javascript is loaded, and than i use boolen in setInterval to start counting only after the all javascript is loaded.
var loadIn - checks if javascript is loaded ,and sets loadIn.jsLoad =true.
if(loadIn.jsLoad) { that.stepFnc(); }
Code checking if
javascript is loaded : this.jsLoad = true (mainly i need this),
html is loaded : this.htmlLoad= true,
both js and html are loaded: this.bLoaded =true
console.log('loading check started' );
var loadProt = function () {
this.bLoaded = "";
this.checkLoadInt="";
this.jsLoadFnc="";
this.bDomainCheckPass = false; //assumes that domain is wrong
this.beforeunload = ""; //event
this.jsLoad = false;
this.htmlLoad = false;
this.bLoaded =false;
};
loadProt.prototype.checkLoadFnc = function() {
console.log('startedFnc checkLoadFnc');
this.htmlLoad = false;
this.jsLoad = false;
if(document.getElementById("bottomPreloadSpan")) { this.htmlLoad =true; }
this.jsLoad = this.jsLoadFnc();
console.log( 'htmlLoad='+this.htmlLoad +', jsLoad=' +this.jsLoad ) ;
this.bLoaded = this.htmlLoad && this.jsLoad;
if( this.bLoaded ) {
this.stopIntervalFnc();
}
};
loadProt.prototype.stopIntervalFnc = function() {
console.log('startedFnc stopIntervalFnc');
document.getElementById("preloadSpan").style.visibility = "hidden";
var preloadImg = document.getElementById('preloadImage');
preloadImg.parentNode.removeChild(preloadImg);
clearInterval(this.checkLoadInt);
this.bDomainCheckPass = this.checkAllowedDomains(); // i do not give it here
//this.evalStep();
if(this.bDomainCheckPass) {
console.log('ERROR right domain');
} else {
console.log('ERROR Wrong domain');
//window.location.assign loads a new document - to login page, saying you was redirected ....
}
}
var loadIn = new loadProt();
loadIn.checkLoadInt = window.setInterval(
function() { loadGIn.checkLoadFnc(); }, 1000 );
loadIn.jsLoadFnc = document.onreadystatechange = function () { return (document.readyState=='complete') ? true : false ; }
Counter function:
var stepProt = function () {
console.log('started stepFnc constructor');
this.step = 20; //seconds
this.cnt = 0; //init counter, pointer to rtArr
};
stepProt.prototype.countingFnc = function () {
console.log('started stepFnc.prototype.countingFnc');
var msec = this.step*1000;
var that = this;
that.cnt=0;
this.nameToStop = window.setInterval( function () {
if(loadIn.jsLoad) { that.stepFnc(); }
}, msec );
}
stepProt.prototype.stepFnc = function() {
console.log (' 132 started stepFnc, this.cnt='+this.cnt );
/* here there is some logics, which takes time */
this.cnt++;
};
var stepIn = new stepProt(); //instance
stepIn.countingFnc();

Jquery Mobile stopwatch

Im trying to make a stopwatch in a JqueryMobile app. I've been following the guide from a previous post How to create a stopwatch using JavaScript?
This works but the function to create the button, essential just makes 3 links, where as I want them as buttons. So at present it will generate the html of:
start
where as I need it to be
start
I've played around with the function to try to get it to work, and even just added my own buttons into the HTML with hrefs of #start, #stop, #reset but cant get them to work
The function is:
function createButton(action, handler) {
var a = document.createElement("a");
a.href = "#" + action;
a.innerHTML = action;
a.addEventListener("click", function(event) {
handler();
event.preventDefault();
});
return a;
}
Add the classes ui-btn ui-btn-inline to the links in createButton. As you are using jQuery anyway, I hvae also updated the stopwatch to use jQuery for DOM manipulation:
(function($) {
var Stopwatch = function (elem, options) {
var timer = createTimer(),
startButton = createButton("start", start),
stopButton = createButton("stop", stop),
resetButton = createButton("reset", reset),
offset,
clock,
interval;
// default options
options = options || {};
options.delay = options.delay || 1;
var $elem = $(elem);
// append elements
$elem.empty()
.append(timer)
.append(startButton)
.append(stopButton)
.append(resetButton);
// initialize
reset();
// private functions
function createTimer() {
return $('<span class="swTime"></span>');
}
function createButton(action, handler) {
var a = $('<a class="' + action + ' ui-btn ui-btn-inline">' + action + '</a>');
a.on("click",function (event) {
handler();
event.preventDefault();
});
return a;
}
function start() {
if (!interval) {
offset = Date.now();
interval = setInterval(update, options.delay);
}
}
function stop() {
if (interval) {
clearInterval(interval);
interval = null;
}
}
function reset() {
clock = 0;
render();
}
function update() {
clock += delta();
render();
}
function render() {
timer.text(clock / 1000);
}
function delta() {
var now = Date.now(),
d = now - offset;
offset = now;
return d;
}
// public API
this.start = start;
this.stop = stop;
this.reset = reset;
};
$.fn.stopwatch = function(options) {
return this.each(function(idx, elem) {
new Stopwatch(elem, options);
});
};
})(jQuery);
$(document).on("pagecreate","#page1", function(){
$(".stopwatch").stopwatch();
});
DEMO

How to delay a JavaScript JSON stream for one minute?

I am ask to write a java script program that retrieve an api JSON record from and address and through websocket every single minute. The stream continues after 60 seconds. I am expected to return the respective stream retrieve and the stream from the previous retrieve . Below is my code
var obj=
{
seconds : 60,
priv : 0,
prevTick : '' ,
data : ''
}
function countTime()
{
obj.seconds --;
obj.priv ++;
var msg ;
if(obj.priv > 1)
{
obj.priv = 0;
obj.msg = null;
}
if(prop.seconds < 0)
{
msg = sock.open();
obj.msg = obj.msg + ", New Tick : " + msg.msg ;
setTimeout(countTime, 1000);
obj.seconds = 60;
}
}
var sock= new WebSocket('link');
sock.onopen = function(evt) {
ws.send(JSON.stringify({ticks:'string'}));
};
sock.onmessage = function(msg) {
var data = JSON.parse(msg.data);
return 'record update: %o'+ data ;
};
Please what is wrong with my code above ? It does not delay at all. The stream continues irrespective.
How about encapsulating the buffering behavior into a class?
function SocketBuffer(socket, delay, ontick) {
var messages = [], tickInterval;
socket.onmessage = function(msg) {
messages.push( JSON.parse(msg.data) );
};
function tick() {
if (typeof ontick !== "function") return;
ontick( messages.splice(0) );
}
this.pause = function () {
tickInterval = clearInterval(tickInterval);
};
this.run = function () {
if (tickInterval) return;
tickInterval = setInterval(tick, delay * 1000);
tick();
};
this.run();
}
Note that .splice(0) returns all elements from the array and empties the array in the same step.
Usage:
var link = new WebSocket('link');
link.onopen = function (evt) {
this.send( JSON.stringify({ticks:'string'}) );
};
var linkBuf = new SocketBuffer(link, 60, function (newMessages) {
console.log(newMessages);
});
// if needed, you can:
linkBuf.pause();
linkBuf.run();
Try this:
function countTime() {
var interval = 1000; // How long do you have to wait for next round
// setInterval will create infinite loop if it is not asked to terminate with clearInterval
var looper = setInterval(function () {
// Your code here
// Terminate the loop if required
clearInterval(looper);
}, interval);
}
If you use setTimeout() you don't need to count the seconds manually. Furthermore, if you need to perform the task periodically, you'd better use setInterval() as #RyanB said. setTimeout() is useful for tasks that need to be performed only once. You're also using prop.seconds but prop doesn't seem to be defined. Finally, you need to call countTime() somewhere or it will never be executed.
This might work better:
var obj=
{
seconds : 60,
priv : 0,
prevTick : '' ,
data : ''
}
function countTime()
{
obj.seconds --;
obj.priv ++; //I don't understand this, it will always be set to zero 3 lines below
var msg ;
if(obj.priv > 1)
{
obj.priv = 0;
obj.msg = null;
}
msg = sock.open();
obj.msg = obj.msg + ", New Tick : " + msg.msg;
obj.seconds = 60;
//Maybe you should do sock.close() here
}
var sock= new WebSocket('link');
sock.onopen = function(evt) {
ws.send(JSON.stringify({ticks:'string'}));
};
sock.onmessage = function(msg) {
var data = JSON.parse(msg.data);
return 'record update: %o'+ data ;
};
var interval = setInterval(countTime, 1000);
EDIT: finally, when you're done, just do
clearInterval(interval);
to stop the execution.

Looping functions with timeout

I want to have two functions (an animation downwards and animation upwards) executing one after the other in a loop having a timeout of a few seconds between both animations. But I don't know how to say it in JS …
Here what I have so far:
Function 1
// Play the Peek animation - downwards
function peekTile() {
var peekAnimation = WinJS.UI.Animation.createPeekAnimation([tile1, tile2]);
// Reposition tiles to their desired post-animation position
tile1.style.top = "-150px";
tile2.style.top = "-150px";
peekAnimation.execute();
}
Function 2
// Play the Peek animation - upwards
function unpeekTile() {
var peekAnimation = WinJS.UI.Animation.createPeekAnimation([tile1, tile2]);
// Reposition tiles to their desired post-animation position
tile1.style.top = "0px";
tile2.style.top = "0px";
peekAnimation.execute();
}
And here's a sketch how both functions should be executed:
var page = WinJS.UI.Pages.define("/html/updateTile.html", {
ready: function (element, options) {
peekTile();
[timeOut]
unpeekTile();
[timeOut]
peekTile();
[timeOut]
unpeekTile();
[timeOut]
and so on …
}
});
You can do this using setTimeout or setInterval, so a simple function to do what you want is:
function cycleWithDelay() {
var delay = arguments[arguments.length - 1],
functions = Array.prototype.slice.call(arguments, 0, arguments.length - 1),
pos = 0;
return setInterval(function () {
functions[pos++]();
pos = pos % functions.length;
}, delay);
}
Usage would be like this for you:
var si = cycleWithDelay(peekTile, unpeekTile, 300);
and to stop it:
clearInterval(si);
This will just cycle through the functions calling the next one in the list every delay msec, repeating back at the beginning when the last one is called. This will result in your peekTile, wait, unpeekTile, wait, peekTile, etc.
If you prefer to start/stop at will, perhaps a more generic solution would suit you:
function Cycler(f) {
if (!(this instanceof Cycler)) {
// Force new
return new Cycler(arguments);
}
// Unbox args
if (f instanceof Function) {
this.fns = Array.prototype.slice.call(arguments);
} else if (f && f.length) {
this.fns = Array.prototype.slice.call(f);
} else {
throw new Error('Invalid arguments supplied to Cycler constructor.');
}
this.pos = 0;
}
Cycler.prototype.start = function (interval) {
var that = this;
interval = interval || 1000;
this.intervalId = setInterval(function () {
that.fns[that.pos++]();
that.pos %= that.fns.length;
}, interval);
}
Cycler.prototype.stop = function () {
if (null !== this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
}
Example usage:
var c = Cycler(peekTile, unpeekTile);
c.start();
// Future
c.stop();
You use setInterval() to call unpeekTile() every 1000 milliseconds and then you call setTimeOut() to run peekTile() after 1000 milliseconds at the end of the unpeekTile() function:
function peekTile() {
var peekAnimation = WinJS.UI.Animation.createPeekAnimation([tile1, tile2]);
// Reposition tiles to their desired post-animation position
tile1.style.top = "-150px";
tile2.style.top = "-150px";
peekAnimation.execute();
}
function unpeekTile() {
/* your code here */
setTimeout(peekTile, 1000);
}
setInterval(unpeekTile, 1000);
Check out the fiddle
var animation = (function () {
var peekInterval, unpeekInterval, delay;
return {
start: function (ip) {
delay = ip;
peekInterval = setTimeout(animation.peekTile, delay);
},
peekTile: function () {
//Your Code goes here
console.log('peek');
unpeekInterval = setTimeout(animation.unpeekTile, delay);
},
unpeekTile: function () {
//Your Code goes here
console.log('unpeek');
peekInterval = setTimeout(animation.peekTile, delay);
},
stop: function () {
clearTimeout(peekInterval);
clearTimeout(unpeekInterval);
}
}
})();
animation.start(1000);
// To stop
setTimeout(animation.stop, 3000);
​
I can't use this instead of animation.peekTile as setTimeout executes in global scope

Categories

Resources