Failing to override JS functions - javascript

I'm trying to override some functions from a lib called log4javascript.
I tried the following:
var _logFatal = log.fatal;
var _logError = log.error;
var _logWarn = log.warn;
var _logDebug = log.debug;
log.fatal = function(message){
return _logFatal(stackTrace(message));
};
log.error = function(message){
return _logError(stackTrace(message));
};
log.warn = function(message){
return _logWarn(stackTrace(message));
};
log.debug = function(message){
return _logDebug(stackTrace(message));
};
But it doesn't work, when I call log.warn('test') for instance, it fails with Uncaught TypeError: object is not a function. But it works fine if I remove that part of the code.
What did I do wrong?

What you are trying to do is what I've seen called "monkey-patching".
I believe the problem you are having is that you are not invoking the functions you are trying to extend with the correct scope.
Try this pattern:
var fnPreviousFatal = log.fatal;
log.fatal = function(message) {
fnPreviousFatal.apply(this, [message]);
}

Related

Overriding prototype.toString doesn't work

I have the following code.
function Test() {
this.myTest = "Test";
}
Test.prototype.toString = function testToString() {
return this.myTest;
};
var test = new Test();
console.log(test);
I expect this to print Test, but it prints Test { myTest: 'Test' }. I thought that overriding toString should use that new function whenever it tries to convert to a string. Any ideas why this isn't working?
According to the specifications (console.log --> Logger --> Printer) the implementation of console.log is ultimately up to the implementation.
So, it is likely that in the environment you are working in the implementation of console.log(obj) is not simply Printer("log", obj.toString()).
function Test() {
this.myTest = "Test";
}
Test.prototype.toString = function testToString() {
return this.myTest;
};
var test = new Test();
console.log(test.toString());
Based on some of the answers here I was able to solve this by using the following code. Although it's similar to some existing answers it is slightly different so decided to post it here.
function Test() {
this.myTest = "Test";
}
Test.prototype.toString = function testToString() {
return this.myTest;
};
var test = new Test();
console.log(test + "");
So just adding + "" to the end of the console.log works perfectly and will run the toString function.

Socket.io + node : TypeError: Object #<Namespace> has no method

I have a simple JavaScript class like that :
function MySIOClass(io)
{
this.io = io
this.ns = this.io.of('/notif')
this.init()
}
MySIOClass.prototype.init = function (){
this.ns.on('connection', this.newClient)
}
MySIOClass.prototype.newClient = function (socket)
{
socket.on('msg', function (data){ this.handle_msg(data)})
 }
MySIOClass.prototype.handle_msg = function (data)
{
// handle my message
}
I get stuck on the function newClient, each time a socket.io client send an event 'msg', the console triggers
TypeError: Object #<Socket> has no method 'handle_msg'
I tried to keep a reference of the operator this inside the function newClient like that :
MySIOClass.prototype.newClient = function (socket)
{
var c = this;
socket.on('msg', function (data){ c.handle_msg(data)})
 }
But no luck too, i got the following error about namespace :
TypeError: Object #<Namespace> has no method 'handle_msg'
My class is exported via a module, everything works except when i try to add a listener with the on method of socket.io inside a class. I have correctly used the "new" operator when i instantiated my class.
Could you help me figure out what's happening ? i tried several things, but none of them worked.
Thanks for your time.
When you pass this.newClient to .on('connection', ...), you are passing just the function itself and losing the (this) context. You need to either create a wrapper function that can access the correct context to call newClient() properly or create a bound version of newClient.
First option:
MySIOClass.prototype.init = function (){
var self = this;
this.ns.on('connection', function(socket) {
self.newClient(socket);
});
}
Second option:
MySIOClass.prototype.init = function (){
this.ns.on('connection', this.newClient.bind(this));
}
Regarding the error inside newClient() itself, you are correct in that you have to use a "self"/"that" variable that you can use to access the correct context to call handle_msg().

AngularJS : undefined is not a function from factory

I have multiple functions inside of my factory and I cannot call my saveCharacter function from a button click using ng-click. The getCharacters function works just fine. Sorry in advance for the repost, I have gone over many different examples and cannot solve my particular issue with those. I can see my functions when I log the xmlService, but i'm not sure why it won't call to it. I was trying to return a post to a PHP file in saveCharacter, but changed to a string return to try to test to see what my issue was.
Thanks again for any help.
(function(){
var app = angular.module('arena', []);
app.factory('xmlService', function($http){
var factory = {};
factory.getCharacter = function getCharacter(){
return $http.get('xml/characterTemplate.xml');
};
factory.saveCharacter = function saveCharacter(){
return "hello";
//return $http.post('php/crud.php');
};
return factory;
});
app.controller('FighterController', ['$scope','xmlService', function($scope, xmlService){
this.fighterList = fighterList;
$scope.saveFighter = function saveFighter(){
console.log(xmlService);
xmlService.saveCharacter.success(function(data){
console.log(data);
});
}
function loadFighters(){
xmlService.getCharacter().success(function(data){
var x2js = new X2JS();
var charactersList = x2js.xml_str2json(data);
for(var i = 0; i < charactersList.characters.character.length; i++)
{
var currentFighter = charactersList.characters.character[i];
fighterList.push(currentFighter);
}
$scope.FighterController = charactersList;
});
}
loadFighters();
}]);
var fighterList = [
];
})();
Other questions I had while writing my first Angular app, what is the point of the code:
$scope.FighterController = charactersList;
does that allow me to access the returned data on the view side? do I have to reset the scope in my saveFighter function to cause my button to work?
Am I setting the dependencies correctly for my app.controller, and is that dependency injection?
Thank you all, and any comments on how my code is setup are greatly appreciated!
You haven't really explained what you did to fix this issue, so I'll explain it.
Here, you are trying to call xmlService.saveCharacter.success():
xmlService.saveCharacter.success(function(data){
console.log(data);
});
But xmlService.saveCharacter is a function. It has no success property; success is undefined. So this gives the error you were seeing.
You need to call xmlService.saveCharacter():
xmlService.saveCharacter().success(function(data){
console.log(data);
});
But this is still a problem because the saveCharacter() function returns the string "hello". This string doesn't have a success property. Yet again success is undefined, so now that causes the same error.
To fix that error, you just need to remove the return "hello"; and uncomment the code you had commented out:
factory.saveCharacter = function saveCharacter(){
return $http.post('php/crud.php');
};
Fixing those two problems should remedy your issue.
You are missing invoking a function with () change code to:
$scope.saveFighter = function saveFighter(){
console.log(xmlService);
xmlService.saveCharacter().success(function(data){
// ----------------------^
console.log(data);
});
}
$scope.FighterController = charactersList;is assigning data of characterList to scope variable and scope variable are accessible in html scope is like a bridge between controller and views.
I recommend you to start reading angularjs
I adjusted my factory to this structure and now I can call my functions.
app.factory('xmlService', function($http){
var factory = {
getCharacter: function(){
return $http.get('xml/characterTemplate.xml');
},
saveCharacter:function(){
console.log('hello?');
return $http.post('php/crud.php');
}
};
return factory;
});
in my controller
$scope.saveFighter = function(){
console.log(xmlService);
xmlService.saveCharacter().success(function(data){
console.log(data);
});
}
function loadFighters(){
xmlService.getCharacter().success(function(data){
var x2js = new X2JS();
var charactersList = x2js.xml_str2json(data);
for(var i = 0; i < charactersList.characters.character.length; i++)
{
var currentFighter = charactersList.characters.character[i];
fighterList.push(currentFighter);
}
$scope.FighterController = charactersList;
});
}
loadFighters();

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.

code snippet works when procedural, but doesn't when converted to modular

function sc_HTMLParser(aHTMLString){
var parseDOM = content.document.createElement('div');
parseDOM.appendChild(Components.classes['#mozilla.org/feed-unescapehtml;1']
.getService(Components.interfaces.nsIScriptableUnescapeHTML)
.parseFragment(aHTMLString, false, null, parseDOM));
return parseDOM;
}
becomes
this.HTMLParser = function(aHTMLString){
var parseDOM = content.document.createElement('div');
parseDOM.appendChild(Components.classes['#mozilla.org/feed-unescapehtml;1']
.getService(Components.interfaces.nsIScriptableUnescapeHTML)
.parseFragment(aHTMLString, false, null, parseDOM));
return parseDOM;
}
and
searchcontents = req.responseText;
parsedHTML = sc_HTMLParser(searchcontents);
sitefound = sc_sitefound(compareuris, parsedHTML);
becomes
searchcontents = req.responseText;
alert(searchcontents);
parsedHTML = this.HTMLParser(searchcontents);
alert(parsedHTML);
sitefound = this.sitefound(compareuris, parsedHTML);
The modular code alerts the search contents, but doesn't alert the parsedHTML. Why? How to solve?
UPDATED:
j0rd4n, it's:
function SiteCompare() {
this.finishSiteCompare = function(downloaduris, compareuris, tryinguri) {
// code
searchcontents = req.responseText;
alert(searchcontents);
parsedHTML = this.HTMLParser(searchcontents);
alert(parsedHTML);
sitefound = this.sitefound(compareuris, parsedHTML);
// code
}
this.HTMLParser = function(aHTMLString) {
//code
}
}
The call is not even being made.
UPDATE:
the Error Console says this.HTMLParser is not a function
The problem is that this is not the same in the function definition and when it's being called. When HTMLParser is defined, this is the SiteCompare object, when this.HTMLParser(searchContents) is called, this is probably the window object. So the error you are getting means that window.HTMLParser is not a function.
To fix this you'd need to define your HTMLParser method outside of the SiteCompare object, or (probably better) use the SiteCompare object to call HTMLParser. Example:
var parser = new SiteCompare();
parsedHTML = parser.HTMLParser(searchcontents);
Is your calling logic executed in the same function-scope as the this.HTMLParser definition?
Try putting an alert statement inside of HTMLParser and see if the call is even made. It sounds like it is throwing an exception and leaving your script.

Categories

Resources