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.
Related
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 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
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));
I would like invoke a method of an js object within the very same object method via setTimeout:
var ads = {
init: function() {
ads.display_ads();
},
display_ads: function() {
console.log('Displaying Ads');
setTimeout('ads.display_ads()', 5000);
}
}
However, I'm getting this error message:
ads is not defined
setTimeout('ads.display_ads()', 2000);
What am I missing here? How would i alter the string within the setTimeout function?
Thanks for your help!
Edit: I use firefox on mac.
Just change it to ads.display_ads, note that this is not a String. i.e.
var ads = {
init: function() {
ads.display_ads();
},
display_ads: function() {
console.log('Displaying Ads');
setTimeout(ads.display_ads, 5000);
}
}
As #FelixKling points out in his comment below, be careful about what this refers to in ads.display_ads. If ads.display_ads is called via ads.init() or ads.display_ads() this will be the ads Object. However, if called via setTimeout this will be window.
If the context is important though, you can pass an anonymous function to setTimeout, which in turn calls ads.display_ads():
setTimeout(function() {
ads.display_ads();
}, 5000);
or
var self = this;
setTimeout(function() {
self.display_ads();
}, 5000);
try this.display_ads,
I'd recommend you to use this for referencing ads
so the code will be like:
var ads = {
init: function() {
this.display_ads();
},
display_ads: function() {
console.log('Displaying Ads');
setTimeout(this.display_ads, 5000);
}
}
So, like jakeclarkson said, ads.display_ads:
setTimeout(hitch(ads, ads.display_ads), 5000);
The difference is that you should use a "hitch" function:
function hitch(scope, callback) {
return function () {
return callback.apply(scope, Array.prototype.slice.call(arguments));
}
}
This function will ensure that the scope of the callback is your ads object. See MDN for a description of the apply function:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply
The answer of jabclab helped me greatly. I was trying to get a game loop to work, but it seems this was referencing window instead of the object I created. Here is a minimal version of the now running code (it just counts up each second and writes it into a div "content"):
function Game(model, renderer){
this.model = model;
this.renderer = renderer;
this.run = function(){
this.model.update();
this.renderer.draw(this.model);
var self = this;
setTimeout(function(){self.run();}, 1000);
};
}
function Model(){
this.data = 0;
this.update = function(){
this.data++;
};
}
function Renderer(){
this.draw = function(model, interpolation){
document.getElementById("content").innerHTML = model.data;
};
}
var game = new Game(new Model(), new Renderer());
game.run();
Instead of setTimeout(this.run, 1000) I used self instead of this to clarify which object is meant (as suggested by jabclab). Thought I'd add this because I'm using an object constructor and has a slightly different syntax. Especially using ads.method didn't work (because Game is not an object yet I guess), so I had to use the last solution.
I'm writing a little plugin for jQuery and so far I've got this:
(function($){
$.fn.extend({
someFunction: function() {
return this.each(function() {
var obj = $(this);
obj.focus(someInternalFunction(obj));
});
}
});
function someInternalFunction(obj) {
};
})(jQuery);
The problem is, when i attach someFunction to the object, the object gets focus and binding of someInternalFunction on focus event fails.
Then I tried to bind function to wrap the function call in the other function:
obj.focus(function() {
someInternalFunction($(this));
});
This code works, but it isn't pretty at all. Is it possible to bind function on focus without wrapping it in the other function?
$.fn.bindFocus() = function(){
var internalFunction = function(){
var $this = $(this),
self = this;
// try do stuff here
};
return this.each(function(){
$(this).bind('focus', internalFunction);
});
}
$('#myElement').bindFocus();
Hope it'll help ?
EDT. Sorry, first time get you wrong :)
Here:
obj.focus(someInternalFunction(obj));
^^^^^
... you're calling the function, meaning that its return value is the thing that actually ends up being passed to focus(). Instead you want to pass a function to focus(). Given the fact that you want to pass obj to someInternalFunction, you'll have to define an additional function to wrap it all:
obj.focus(function(){
someInternalFunction(obj);
});
Just to make things clear:
var x = function() { return 3; }; // Defining a function
x; // -> this is a function reference
x(); // -> this is 3