I'm making an image scroller that automatically advances the image every few seconds (10 seconds for the sake of debugging) or when the user clicks the image. My code (shown below) works, although I'd like to "reset" the 10 second counter if a manual (click) advancement of the image is done. How can I do this? I seem to be having no luck with clearInterval.
...
setInterval('gallery()',10000);
$("#gallery").click(function() {
clearInverval();// <--- not working
gallery();
});
…
I see others defining a variable as (in my case) setInterval('gallery()',10000); but I couldn't get that to work either =/
PS I have limited knowledge of languages other than C
The setInterval method returns a handle to the interval, which you use to stop it:
var handle = window.setInterval(gallery,10000);
$("#gallery").click(function() {
window.clearInterval(handle);
gallery();
});
May be you can do something like this:
var handle = setInterval(gallery,10000);
$("#gallery").click(function() {
clearInterval(handle);
/*
* your #gallery.click event-handler code here
*/
//finally, set automatic scrolling again
handle = setInterval(gallery,10000);
});
You need to set the setInterval as a variable for this to work..
var interval = setInterval(gallery, 10000);
$('#gallery').click(function() {
clearInterval(interval);
});
I struggled to make a simple pause/continue handler when doing prototype based coding and did not want to use any external plugin because of this.
The code below is pretty self-explanatory and will hopefully save other coders time.
Non-functional example:
/** THIS DID NOT WORK
function Agent( name )
{
this.name = name;
this.intervalID = undefined; // THIS DID NOT WORK!!!
} // constructor
Agent.prototype.start = function( speed )
{
var self = this;
this.intervalID = setInterval( function(){ self.act(); }, speed );
}; // start
Agent.prototype.pause = function()
{
clearInterval( this.intervalID );
console.log( "pause" );
}; // pause
**/
Instead you have to do it like this:
var intervalID = undefined;
function Agent( name )
{
this.name = name;
} // constructor
Agent.prototype.start = function( speed )
{
var self = this;
intervalID = setInterval( function(){ self.act(); }, speed );
}; // start
Agent.prototype.pause = function()
{
clearInterval( intervalID );
console.log( "pause" );
}; // pause
Related
I am currently playing about with the LastFM API and trying to get a Recently Played Tracks list to update as I play tracks through Spotify and ITunes. I have got the initial code working through a combination of JS and Handlebars so that a static list of tracks is loaded in on page load which is current at the time of page load.
However I want the list to update as I select a new track without refreshing the page. So I thought I could just use a setInterval function to call my original function every 5 seconds or so. However for some reason my setInterval function is only running once on page load.
I know that this is a real simple error but I can't work out why? Help!!
var clientname = {};
clientname.website = (function(){
var
initPlugins = function(){
var setupLastFM = (function(){
/* Create a cache object */
var cache = new LastFMCache(),
/* Create a LastFM object */
lastfm = new LastFM({
apiKey : '6db1989bd348bf91797bad802c6645d8',
apiSecret : '155270f02728b1936ed7699e9f7b8de9',
cache : cache
}),
attachTemplate = function(data, handlebarsTemplateID){
var template = Handlebars.compile(handlebarsTemplateID.html());
$(".container").append(template(data));
}
/* Load some artist info. */
lastfm.user.getRecentTracks({user: 'jimmersjukebox'}, {
success: function(data){
var trackData = data.recenttracks.track,
tracks = $.map(trackData, function(track) {
if(track['#attr']){
var isCurrentTrack = true;
}
return {
currenttrack: isCurrentTrack,
song: track.name,
artist: track.artist['#text']
};
});
attachTemplate(tracks, $("#trackInfo"));
}, error: function(code, message){
}}),
intervalID = window.setInterval(console.log("test"), 1000);
}());
}
return{
init: function(){
initPlugins();
}
};
})();
$(window).load(clientname.website.init);
You are running console.log("test") immediately. Try encapsulating this in anther function, but do not instantiate it by including the parenthesis ().
intervalID = window.setInterval(function(){
console.log("test");
}, 1000);
You should not call the function in setInterval. It needs a callback.
Say like bellow
intervalID = window.setInterval(function(){
console.log("test");
}, 1000);
I would recommend to use setTimeout: Use a function to contain the setTimeout, and call it within the function:
$(function() {
var current = $('#counter').text();
var endvalue = 50;
function timeoutVersion() {
if (current === endvalue) {return false;} else {
current++;
$('#counter').text(current);
}
setTimeout(timeoutVersion, 50);
}
$('a').click(function() {
timeoutVersion();
})
})
JS Fiddle
You used a function call instead of a function reference as the first parameter of the setInterval. Do it like this:
function test() {
console.log("test");
}
intervalID= window.setInterval(test, 1000);
or you can do this also:
intervalID= window.setInterval( function() {
console.log("test!");
}, 1000);
I'm using code from a JSFiddle to implement a count up feature on my site. I like it because it allows me to target a number displayed in a specific div, and I don't need to specify that number in the javascript, which means I can use it on any page for any number I choose.
See the code here:
// basic class implementation
function myCounter() {
// privileged property for iteration
this.i = 0;
// privileged init method
this.init();
}
// defining init method
myCounter.prototype.init = function () {
// reassign this
var _this = this;
setInterval(function () {
// call this.countUp() using our new created variable.
// this has to be done as this would normally call something
// inside this function, so we have to pass it as own
// variable over
_this.countUp();
}, 500);
clearInterval(function () {
this.i ==
};
};
// defining the counter method
myCounter.prototype.countUp = function () {
this.i++;
document.getElementById('counter').innerHTML = this.i;
};
// create a new instance of our counter class
var counter = new myCounter();
The only problem is that it doesn't stop counting. I'd love to add some code for that myself, except I'm not familiar enough with javascript and have no idea where to start.
Is there a way to tell javascript to stop counting at the number specified in the targeted div?
Thanks so much!
// basic class implementation
function myCounter() {
// privileged property for iteration
this.i = 0;
// privileged init method
this.init();
}
// defining init method
myCounter.prototype.init = function () {
// reassign this
var _this = this;
this.timer = setInterval(function () {
// call this.countUp() using our new created variable.
// this has to be done as this would normally call something
// inside this function, so we have to pass it as own
// variable over
_this.countUp();
}, 500);
};
// defining the counter method
myCounter.prototype.countUp = function () {
this.i++;
document.getElementById('counter').innerHTML = this.i;
// stop the timer
if(this.i == 8){
clearInterval(this.timer)
}
};
// create a new instance of our counter class
var counter = new myCounter();
I'm trying to create a simple game loop and trying to use OOP paradigm in JS. Here is my code:
HTML
<body onload="Game.OnLoad('gameField')" onkeydown="Game.KeyDown(event)">
<p id="info">1</p>
<p id="info2">2</p>
<canvas id="gameField"
width="896px"
height="717px"
class="game-field"
style="border: 4px solid aqua"
onclick="Game.MouseClick(event)"></canvas>
</body>
JavaScript
// class Timer
// version: 1
// only tick() functionality available
// right now
function Timer() {
var date = new Date();
var prevTick = 0;
var currTick = 0;
// update timer with tick
this.tick = function() {
prevTick = currTick;
currTick = date.getTime();
}
// get time between two ticks
this.getLastTickInterval = function() {
return currTick - prevTick;
}
}
// global object Game
// which handles game loop
// and provide interfaces for
var Game = new function() {
// variables:
this.canvas = 0;
var gameLoopId = 0;
this.timer = new Timer();
// events:
this.KeyDown = function(e) {}
// game loop:
this.Run = function() {
this.timer.tick();
this.Update(this.timer.getLastTickInterval());
this.Draw();
}
this.Update = function(dt) {
document.getElementById("info").innerHTML = dt;
}
this.Draw = function() {}
this.StopGameLoop = function() {
clearInterval(gameLoopId);
}
this.OnLoad = function(canvasName) {
this.canvas = document.getElementById(canvasName);
this.timer.tick();
// start game loop
setInterval(this.Run, 1000);
}
}
(Fiddle)
I'm trying to make Game class global. Other classes must be instantinated using new.
Classes Game and Timer are placed in different files called Game.js and Timer.js. When I run this code in Chrome I got an error in DevTools: "Uncaught TypeError: Cannot call method 'tick' of undefined" in Game.Run function at the line this.timer.tick();
So I wonder, what is the problem with my code? Thanks for reply.
Your problem is with the context. When you're calling tick this is window, not Game.
You can handle this, for example, by setting:
var self = this;
this.Run = function() {
self.timer.tick();
self.Update(self.timer.getLastTickInterval());
self.Draw();
}
Few things to consider in your code :
Concerning your issue, methode like setInterval or setTimeout loose the context. Easiest solution is to bind a context to the callback :
setInterval(this.Run.bind(this), 1000);
Secondly, avoid adding private methode inside an object function. In that case, every instance of Game will have its own set of functions (memory leak).
Prefer using prototypes :
function Game () {
this.canvas = null;
}
Game.prototype = {
init: function() {}
render: function () {}
};
Lastly, I see you redraw every seconds, which is ok. But if you want 60fps, you can use requestAnimationFrame for drawing oriented loops.
ps: just to be very nitpicking, functions' name should be camelCase so starting with lower case.
I have always had trouble working with time events. Could someone please explain why A doesn't work and B does? The only difference is in A I put the event binding in a function. Don't worry about the function close, it has nothing to do with the question. When I test A, there is no js errors but timer is not cleared.
A ->
Test.Navigation = (function() {
var openTimer = null;
var closeTimer = null;
var addListeners = function() {
$('.hover_container').on('mousemove', function(e) {
clearTimeout(closeTimer);
});
$('.hover_container').on('mouseleave', function(e) {
// set the close timer
var container = this;
closeTimer = setTimeout(function() {
//has the mouse paused
close(container);
}, 750);
});
};
return {
init : function() {
addListeners();
}
};
})();
B ->
Test.Navigation = (function() {
var openTimer = null;
var closeTimer = null;
$('.hover_container').on('mousemove', function(e) {
clearTimeout(closeTimer);
});
$('.hover_container').on('mouseleave', function(e) {
// set the close timer
var container = this;
closeTimer = setTimeout(function() {
//has the mouse paused
close(container);
}, 750);
});
var addListeners = function() {
// nothing here
};
return {
init : function() {
addListeners();
}
};
})();
Edit: Please ignore the container part, it has nothing to dow ith the question it is simply part of the full code that I did not take out
A is binded before the object exists where the init is called. Because your return a new object. If you are using, 2 objects are created. 1 with the vars en binds. and 1 with the returns.
B is working because you create a function where the elements are initialized and use the right scope. A is not working because the bindings are on the wrong scope because your create 2 objects:
new Test.Navigation(); // Create 1 object
// Create second object.
return {
init : function() {
addListeners();
}
};
Youd better get a structure like this, then it should work aswell:
Test.Navigation = (function() {
// Private vars. Use underscore to make it easy for yourself so they are private.
var _openTimer = null,
_closeTimer = null;
$('.hover_container').on('mousemove', function(e) {
clearTimeout(_closeTimer );
});
$('.hover_container').on('mouseleave', function(e) {
// set the close timer,
// use $.proxy so you don't need to create a exta var for the container.
_closeTimer = setTimeout(
$.proxy(function() {
//has the mouse paused
close(this);
}, this)
, 750);
});
this.addListeners = function() {
// nothing here
};
this.init = function() {
this.addListeners();
}
// Always call the init?
this.init();
return this; // Return the new object Test.Navigation
})();
And use it like
var nav = new Test.Navigation();
nav.init();
Also as you can see I upgraded your code a bit. Using $.proxy, _ for private vars.
Your use of this is in the wrong scope for the first approach.
Try
var openTimer = null;
var closeTimer = null;
var self = this;
and then later
var container = self;
In your code for example A,
$('.hover_container').on('mouseleave', function(e) {
// set the close timer
var container = this;
this is actually referring to the current $('.hover_container') element.
Also, since setTimeout will wait before the previous setTimeout finishes to start again, you can get discrepancies. You may want to switch to setInterval because it will issue its callback at every interval set regardless of if the previous callback has completed.
My guess is that in the calling code, you have a statement new Test.Navigation() which, for B, addListeners is called at the time of new Test.Navigation(). In A, you return an object ref that calls an init function. Can you verify that init() is called?
I.e. in A, init() has to be called before the handlers are added. In B, the handlers are added everytime you instantiate Test.Navigation --- which, depending on the calling code, could be bad if you intend to instantiate more than one Test.Navigation() at a time.
I need to know what I am doing wrong because I cannot call the internal functions show or hide?
(function()
{
var Fresh = {
notify:function()
{
var timeout = 20000;
$("#notify-container div").get(0).id.substr(7,1) == "1" && (show(),setTimeout(hide(),timeout));
var show = function ()
{
$("body").animate({marginTop: "2.5em"}, "fast", "linear");
$("#notify-container div:eq(0)").fadeIn("slow");
},
hide = function()
{
$("#notify-container div").hide();
}
}//END notify
}
window.Fresh = Fresh;
})();
Fresh.notify();
thanks, Richard
UPDATE
If you wanted to be able to do something like: Fresh.notify.showMessage(), all you need to do is assign a property to the function notify:
var Fresh = {notify:function(){return 'notify called';}};
Fresh.notify.showMessage = function () { return this() + ' and showMessage, too!';};
Fresh.notify();//notify called
Fresh.notify.showMessage();//notify called and showMessage, too!
This will point to the function object here, and can be called as such (this() === Fresh.notify();). That's all there is too it.
There's a number of issues with this code. First of all: it's great that you're trying to use closures. But you're not using them to the fullest, if you don't mind my saying. For example: the notify method is packed with function declarations and jQuery selectors. This means that each time the method is invoked, new function objects will be created and the selectors will cause the dom to be searched time and time again. It's better to just keep the functions and the dom elements referenced in the closure scope:
(function()
{
var body = $("body");
var notifyDiv = $("#notify-container div")[0];
var notifyDivEq0 = $("#notify-container div:eq(0)");
var show = function ()
{
body.animate({marginTop: "2.5em"}, "fast", "linear");
notifyDivEq0.fadeIn("slow");
};
var hide = function()
{//notifyDiv is not a jQ object, just pass it to jQ again:
$(notifyDiv).hide();
};
var timeout = 20000;
var Fresh = {
notify:function()
{
//this doesn't really make sense to me...
//notifyDiv.id.substr(7,1) == "1" && (show(),setTimeout(hide,timeout));
//I think this is what you want:
if (notifyDiv.id.charAt(6) === '1')
{
show();
setTimeout(hide,timeout);//pass function reference
//setTimeout(hide(),timeout); calls return value of hide, which is undefined here
}
}//END notify
}
window.Fresh = Fresh;
})();
Fresh.notify();
It's hard to make suggestions in this case, though because, on its own, this code doesn't really make much sense. I'd suggest you set up a fiddle so we can see the code at work (or see the code fail :P)
First, you're trying to use show value when it's not defined yet (though show variable does exist in that scope):
function test() {
show(); // TypeError: show is not a function
var show = function() { console.log(42); };
}
It's easily fixable with moving var show line above the point where it'll be called:
function test() {
var show = function() { console.log(42); };
show();
}
test(); // 42
... or if you define functions in more 'traditional' way (with function show() { ... } notation).
function test() {
show();
function show() { console.log(42); };
}
test(); // 42
Second, you should use this instead:
... && (show(), setTimeout(hide, timeout) );
... as it's the function name, and not the function result, that should be passed to setTimeout as the first argument.
You have to define show and hide before, also change the hide() as they said.
The result will be something like this:
(function()
{
var Fresh = {
notify:function()
{
var show = function()
{
$("body").animate({marginTop: "2.5em"}, "fast", "linear");
$("#notify-container div:eq(0)").fadeIn("slow");
},
hide = function()
{
$("#notify-container div").hide();
},
timeout = 20000;
$("#notify-container div").get(0).id.substr(7,1) == "1" && ( show(), setTimeout(hide,timeout) );
}//END notify
}
window.Fresh = Fresh;
})();
Fresh.notify();
I think order of calling show , hide is the matter . I have modified your code . It works fine . Please visit the link
http://jsfiddle.net/dzZe3/1/
the
(show(),setTimeout(hide(),timeout));
needs to at least be
(show(),setTimeout(function() {hide()},timeout));
or
(show(),setTimeout(hide,timeout));