Object with eventhandler overloading - javascript

Currently I'm trying to write a resourcemanager in JavaScript. It has two methods, one to add a image resource to the manager, and one that preloads all the images after they are added:
ResourceManager = function(){};
ResourceManager.prototype = function(){
var imageList = new Array(),
addImage = function(imageUrl){
imageList.push(imageUrl);
},
loadImages = function(){
//Do stuff for loading here
onComplete();
},
onComplete = function(){
alert('finished');
};
return {
addImage: addImage,
loadImages: loadImages,
onComplete: onComplete
}
}();
Then I want to use it as following:
var rsmgr = new ResourceManager();
rsmgr.onComplete = function(){
alert('completed');
};
rsmgr.addImage('image.png');
rsmgr.loadImages();
You can see a working example on jsfiddle
Now this overload is not working, so why does this happen? I'm guessing it has to do with the prototyping but I can't seem to grasp on how to fix this.

I'm no expert in prototyping, so can't give valid response why it's not working however I can suggest alternative way using "pure function" approach that works just fine:
function ResourceManager() {
this.imageList = new Array();
this.addImage = function(imageUrl) {
this.imageList.push(imageUrl);
};
this.loadImages = function() {
//Do stuff for loading here
this.onComplete();
};
this.onComplete = function() {
alert('finished');
};
};
Having it written like the above cause your original override code to work - updated fiddle.
(If you remove the rsmgr.onComplete override you'll get "finished" as expected)

Related

Tiny JavaScript library stopped working

For a previous question I answered here on SO, I made the following library.
(function(){
var LS = function(){
return new LS.fn.init();
};
LS.fn = LS.prototype ={
//Check to see if the browser suports LocalStorage
init : function(){
this.ls = (typeof(Storage)!=="undefined") ? false : true;
return this;
}
}
LS.fn.init.prototype = LS.fn;
LS.fn.init.prototype = {
set : function(name, val){
if(this.ls) localStorage.setItem(name, val);
},
get : function (name){
if(this.ls) return localStorage.getItem(name);
},
remove : function(name){
if(this.ls) localStorage.removeItem(name);
},
test: function(){
alert("hi")
}
}
window.LS = window.ls = LS;
})();
This was working fine until recently.
I am getting errors like:
LS.set("foo", "bar"); // Error: undefined is not a function...
Even the following code gives an error:
LS.test();
Why has this stopped working?
Thank you.
NOTE: Previously, I had a typo, but now I have fixed that and it still doesn't work.
Your window.LS is initialized to a function, and you seem to use it as if you expect it to be initialized to the return value of that function.
Change this line:
window.LS = window.ls = LS;
to:
window.LS = window.ls = LS();
Also, try to simplify your library code. It seems very convoluted. At the very least comment it out a bit to indicate what the various parts do/are used for. The part with the typo (LS.protorype) isn't used anywhere for example.

How do you handle with control binding in jquery

I have a question about jquery and DOM manipulation. How do you handle with DOM controls for e.g.
I have to get value from text input so I could this in ways:
var SomeClass = function() {
var control;
this.setControl = function(c) {
control = c;
}
this.getValue = function() {
return control.val();
}
}
$(document).ready(function() {
var sc = new SomeClass(); // of course control could be passed in contructor as well
sc.setControl($('#CONTROL'));
console.log(sc.getValue());
});
OR
var SomeClass = function() {
var control = $('#CONTROL');
this.getValue = function() {
return control.val();
}
}
$(document).ready(function() {
var sc = new SomeClass();
console.log(sc.getValue());
});
what is your opinion? What is better or maybe this is pile of trash therefore what is the best solution. Plz dont send me to backbone, spine and so on Im interesed in only in jquery.
best!
EDIT:
do you separate logic from UI or you are mixing it?
more complicated example
in js file you have a class that uses text control and in the secound js file also you need values from this input. What you are doing? you just call everytime $('#control') or create a third js file where would be a separated "class" to manipulate this input?
It would make more sense to move the setValue() inside the constructor:
SomeClass = function(c) {
var control = c;
return {
getValue: function() {
return control.val();
}
}
}
var x = new SomeClass($('input'));
alert(x.getValue());
However, I'm not sure how valuable this kind of information hiding will be. Perhaps as some kind of view wrapper.
In many cases you wouldn't need this wrapper, so just:
var $x = $('input'); // keep reference to a bunch of <input> elements.

Overriding function in complicated prototype javascript

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, …){
…
};

cannot access function within function in javascript

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));

Self invoking function via setTimeout within object

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.

Categories

Resources