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));
Related
I have tried different things but I do seem to be looking something over that is too obvious. Trying to use the value a function(method) returns inside an object and use it in another method with setTimeout within that same object.
This is the html:
<h1>3000</h1>
The javascript (jQuery in this case):
var foo = {
getValue: function() {
var h1Text = $('h1').text();
h1Text = parseInt(h1Text);
return h1Text;
},
useValue: function() {
var time = this.getValue();
var alertIt = alert('Hello');
setTimeout(alertIt,time);
}
};
foo.useValue();
// log shows correct value
console.log(foo.getValue());
// returns a number
console.log(typeof(foo.getValue()));
The alert does show up, but on load rather than using those 3 seconds.
It does log the correct value and also says it's a number so I'm really not sure what I am doing wrong. Any help is appreciated. Thanks
In useValue() you call alert('Hello'), so it's executed immediately and the result is stored in alertIt variable. You should put it inside the function like this, as setTimeout expects a function as a first parameter:
var alertIt = function() {
alert('Hello');
}
setTimeout(alertIt,time);
setTiimeout expects function and not variable.
Also var alertIt = alert('Hello'); this will return undefined.
Note: var a = function() will call it and assign return value. To assign a function to a variable with parameter, use .bind
Try alert.bind(null, "hello");
For demo purpose, I have hardcoded value of delay and commented getValue code.
var foo = {
getValue: function() {
//var h1Text = $('h1').text();
//h1Text = parseInt(h1Text);
return true// h1Text;
},
useValue: function() {
var time = 3000//this.getValue();
var alertIt = alert.bind(null,'Hello');
setTimeout(alertIt, time);
}
};
foo.useValue();
// log shows correct value
console.log(foo.getValue());
// returns a number
console.log(typeof(foo.getValue()));
I wrote a simple tooltip functionality, to be seen here.
The thing is, in both handler functions set in .hover() I need access to $(this) and other 2 variables based on it. In order do achieve that, I declare the same 3 variables in both handlers:
$('a').hover(
function () {
var $this = $(this);
var link_offset = $this.offset();
var link_tooltip = $this.data('tooltip');
// Rest of the code
},
function () {
var $this = $(this);
var link_offset = $this.offset();
var link_tooltip = $this.data('tooltip');
// Rest of the code
}
);
DRY principle should be respected, so my question is: Is there other and smarter/less dirty way of passing the same variables set to both functions within .hover()?
Obvioulsy, the variables can't be global (and globals are evil anyway).
Any ideas how to achieve this with jQuery or pure JS?
Call one named function inside the anonymous callbacks:
$('a').hover(function() {
hoverFunc($(this), true)
}, function() {
hoverFunc($(this), false)
});
function hoverFunc($this, is_hovered) {
var link_offset = $this.offset();
var link_tooltip = $this.data('tooltip');
if (is_hovered) {
console.log('ok')
// do something
} else {
console.log('out')
// do something else
};
}
http://jsfiddle.net/mblase75/8njk2m32/
var fbToggle = document.getElementById("fbToggle");
and later in the script
fbToggle.addEventListener("click", toggle("fbContainer"));
Console tells me that fbToggle is NULL
This is in the document though.
<input type="checkbox" id="fbToggle">
I wasnt using eventListener before, so maybe there is a special order of declaration i'm missing ?
EDIT :
entire js :
function toggle(target) {
var obj = document.getElementById(target);
display = obj.style.display;
if (display == "none") {display = "block"}
else {display = "none"}
}
function init() {
var fbToggle = document.getElementById("fbToggle");
var twitToggle = document.getElementById("twitToggle");
var pinToggle = document.getElementById("pinToggle");
console.log(fbToggle); // NULL
fbToggle.addEventListener("click", toggle("fbContainer"));
twitToggle.addEventListener("click", toggle("twitContainer"));
pinToggle.addEventListener("click", toggle("pinContainer"));
}
window.onload = init();
HTML is way too long.but JS is in head, called from external file. Also i'm not in quirk mode.
It is not clear where "later in the script" is. If it is in different scope definitely it is not going to work. Suggesting you to keep everything in a global object if possible so that you can access from different places in the script.
window.globals = {};
window.globals.fbToggle = document.getElementById("fbToggle");
window.globals.fbToggle.addEventListener("click", function () {
toggle("fbContainer")
});
function toggle(container) {
alert(container);
}
http://jsfiddle.net/ST938/
Another point is addEventListener expects a function or function idenitifier, NOT a function call.
addEventListener("click", toggle("fbContainer")); // wrong
addEventListener("click", toggle); // correct
So if you want to pass a parameter
window.globals.fbToggle.addEventListener("click", function () {
toggle("fbContainer")
});
function toggle(container) {
alert(container);
}
In JavaScript, putting brackets after a function name causes it to be called. If you want to reference a function without calling it you must not put brackets after the name:
window.onload = init(); // this calls init() immediately
window.onload = init; // this correctly stores init in window.onload
The same applies to toggle(). If you need to pre-specify some of the arguments you can wrap it in an anonymous function:
fbToggle.addEventListener("click", function() { toggle("fbContainer"); });
or you can use bind:
fbToggle.addEventListener("click", toggle.bind(null, "fbContainer"));
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'm a bit stuck on a problem which I can't solve, I performed investigation on internet and on this site, but I can't find the answer to my question.
So basically I have a javascript file, which I cannot modify, so I have another javascript file which should catch the method when it is called and override it.
Normally I know how it works and I already done the function overriding, but I don't know how to solve this issue.
I have a very big script, but I will show just a small piece of it:
Microsoft.Office.Server.Ajax.NavResizer.prototype = {
$6: null,
$7: null,
......
$20:function ($p0) {
if (this.$1E) {
$p0.preventDefault();
}
},
$21: function ($p0) {
var $0 = $p0.target;
this.$1F = ($0 === this.$A);
if (this.$1F || $0 === this.$B) {
this.$1E = $0;
this.$18 = $p0.clientX;
this.$19 = $p0.clientY;
Sys.UI.DomEvent.removeHandler(this.$1E, 'mousedown', this.$12);
var $1 = document.body; Sys.UI.DomEvent.addHandler($1, 'mouseup', this.$13);
Sys.UI.DomEvent.addHandler($1, 'mousemove', this.$14);
$1.style.cursor = (this.$1F) ? 'e-resize' : 'n-resize';
this.$1A = this.get_$42();
this.$1B = this.get_$43();
$1.focus();
Sys.UI.DomEvent.addHandler($1, 'selectstart', this.$15);
$p0.preventDefault();
}
},
$22: function ($p0) {
this.$34($p0);
var $0 = document.body;
Sys.UI.DomEvent.removeHandler($0, 'mouseup', this.$13);
Sys.UI.DomEvent.removeHandler($0, 'mousemove', this.$14);
Sys.UI.DomEvent.addHandler($0, 'selectstart', this.$15);
$0.style.cursor = 'default';
Sys.UI.DomEvent.addHandler(this.$1E, 'mousedown', this.$12);
this.$1E = null;
},
$23: function ($p0) {
this.$34($p0);
},
$24: function ($p0) {
this.$26();
},
....
Basically this is the part of the script: so lets say I want to override function: $22: function ($p0) in the script in another javascript file, how do i do that?
I would appreciate any help.
A small update, some good examples were provided but they are not working.
The environment where i run this sript is SharePoint, normally when I did override I used this method:
var oldFixRibbonAndWorkspaceDimensions = window.FixRibbonAndWorkspaceDimensions;
window.FixRibbonAndWorkspaceDimensions = function () {
this.MyFixRibbonAndWorkspaceDimensions();
};
function MyFixRibbonAndWorkspaceDimensions(){...}
And it didn't matter when i load the script as this function was only called when the default function was called not before not after. Just in the same time. But with the example which were provided here, the function is trying to execute on the document.ready()
You want to permanently override it? Just do this:
Microsoft.Office.Server.Ajax.NavResizer.prototype.$22 = function($p0) {
// your code.
};
As long as your script is executed after the original is defined, you're good.
Old post.. but this works for me:
ExecuteOrDelayUntilScriptLoaded(overrideNavResizer, "NavResizer.js");
function overrideNavResizer(){
Microsoft.Office.Server.Ajax.NavResizer.prototype.$22 = function($p0) {
// your code.
};
}
In your new script:
Microsoft.Office.Server.Ajax.NavResizer.prototype.$22 = function () {//your function code}
Assuming you have access to the prototype object (it's in global scope) and your scripts runs after it, that is easy:
var proto = Microsoft.Office.Server.Ajax.NavResizer.prototype,
oldMethod = proto.$22;
proto.$22 = function newMethod(args, …){
…
};