How to make database call without losing this? - javascript

Because database is a separate object in itself, calling it I lose this
var neo4j = require('neo4j');
var db = new neo4j.GraphDatabase('http://localhost:7474');
function MyObject(id){this.id = id}
MyObject.prototype.myQuery = function(){
db.query('Some Query',{args:params},function(callback){
//this in here is some neo4j db related object.
//instead of MyObject
console.log(this.id); //undefined
});
}
myObject = new MyObject(9);
myObject.myQuery(); //undefined
Any workaround to make the database call and still have my this refer to the original intended object from inside the db's callback?

Cache it before the call :
MyObject.prototype.myQuery = function(){
var self = this;
db.query('QUERY',{args:params},function(callback){
//If you use self here, it will work.
console.log(self.id);
});
}

Apart from saving it to a variable, you can also bind this to a function as shown here:
MyObject.prototype.myQuery = function(){
db.query('Some Query',{args:params},function(callback){
//this in here is some neo4j db related object.
//instead of MyObject
console.log(this.id); //undefined
}.bind(this));
}
... or use arrow functions from ES6, even though it's not yet an option...

You can save this before you call the db.query method, like so:
MyObject.prototype.myQuery = function(){
var thisQuery = this;
db.query('QUERY',{args:params},function(callback){
// Now you can use thisQuery to refer to your query object
}
}

Related

why I can't "overwrite" a method in javascript?

I would like to override a function of a JS object by adding it to its prototype.
var originalObject = function(){
this.someFun = function(){
// ...
}
}
var otherObj = function(){
this.otherFun = function(){
originalObject.prototype.fun = function(){
return 'This is the overwritten function.';
}
var o = new originalObject();
return o.fun()
}
}
This way when I execute new otherObj().otherFun() I have the expected result ('This is the overwritten function.'), but if the function I'm trying to add is already part of originalObject
var originalObject = function(){
this.fun = function(){
return 'This is the original function';
}
this.someFun = function(){
// ...
}
}
Then the result is not the expected one, infact new otherObj().otherFun() returns 'This is the original function'.
so, is this the only way to add the method to the prototype and override it? And most important why I can't "overwrite" the function in the prototype?
In js objects there are two levels which are depend on directly object and depend on directly prototype. And when you call a property which is in object, it starts to search from the root then looks in branches. You can see the tree belowed picture:
Because the function already existed in object, it will be called out instead of being looked for in objects prototype.

Knockoutjs observable and jQuery extends function

Let's say I have the following code:
var Klass = function(){
var self = this;
this.value = 123;
this.update = function(){
$.ajax({
url: '/whatever',
async: false,
success: function(data){
$.extend(self, data);
}
});
}
}
Lets assume, '/whatever' returns this json object:
{value: 234}
And when I do this:
var obj = new Klass();
obj = ko.mapping.fromJS(obj);
console.log(obj);
We all know obj is now an knockoutjs observable.
And I run this:
obj.update();
console.log(obj);
What I have discovered is, value of obj doesn't get overridden as a simple value 234, but stayed as an observable property.
My questions are:
1) why is this?
2) How do I make the update work as I wanted.
UPDATE: ajax call is not asynchronous.
First issue is that you are extending self, which is a scoped variable and only exists inside the Klass function, not it's instances you create by calling it.
You'll need to call $.extend(this, data); if you need to overwrite value when calling update.
Although I do understand why you are using self there.
But the observable functionality added by calling ko.mapping.fromJS is then lost. value is no longer a function (ko observable) but a scalar value (234). You have to call obj = ko.mapping.fromJS(obj); again to wrap value as observable.
Second issue is that $.get is asynchronous so calling console.log(obj) right after calling obj.update will log the value before the GET response comes. You need to wait for it to execute (use a callback).
Here's a working fiddle.
var Klass = function(){
this.value = 123;
this.update = function(callback){
var self = this;
$.get('/', function(data) {
$.extend(self, {value: 234});
callback.call(undefined);
});
}
}
var obj = new Klass();
obj = ko.mapping.fromJS(obj);
console.log(obj.value());
obj.update(function() {
obj = ko.mapping.fromJS(obj);
console.log(obj.value());
});

confusion, this-pointer and events in javascript

I have a javascript object which I would like to be able to handle some interactive features. It's a bit tricky to describe the scenario in a simple way so hopefully it'll not get all out of hand here.
my object looks something like
myobject = function() {
this.initialize = function() {
// HERE this = the myobject instance
var test = document.createElement('div');
test.onmousedown = this.mousedown;
}
this.mousedown = function(e) {
// HERE this = the calling div-element
}
}
So my problem is basically that this will not be an myobject instance when this.mousedown(e) is called, it will rather be the caller (if the terminology is correct?) in this case it is the div I created and put in a variable called test above.
I would like to have access to the instance on which the method is being run (as I believe that to be the mousedown method I created).
This far I have had some ideas which I have tried out:
create a data- attribute on the div containing the this object and operate on that.
sending the this pointer as an argument along with e to this.mousedown(e)
It's all I can think of now hope it makes sence.
You could create a copy when you first instantiate the object:
var myobject = function() {
var self = this;
this.initialize() {
// HERE this = the myobject instance
var test = document.createElement('div');
test.onmousedown = this.mousedown;
}
this.mousedown(e) {
// HERE this = the calling div-element
// use self instead of this
}
}
The simplest solution is to make a 'self' var that you refer to in the callback:
myobject = funciton() {
var self = this;
this.initialize() {
//use self to refer to myobject
self.mousedown(e);
}
this.mousedown(e) {
}
}

"this" in JavaScript. reference to an object inside a factory

I wrote some classes in javascript and i wrote a few FunctionFactories for them. But I think that i have done some things wrong.
I renamed some things of my code, that you can understand it better.
So the first class is the "root"-class. this class has children, which i add later.
function templateRoot(){
this.id = "root";
this.parent = null;
this.children = [];
this.editable = true; // bla
this.render = function(){
$.each(this.children,function(i,obj){
this.children[i].render();
var baseButtons = this.getBaseButtons();
$('#'+this.id).append(baseButtons);
});
};
this.addBase = addBaseFactory(this);
};
The attribute "addBase" gets a function which is delivered by addBaseFactory...
function addBaseFactory(that){
return function(){
var newBase = new base(that.children.length, that.id);
that.children.push(newBase);
};
}
...and the base class which is used to generate a object in "addBase" looks like this:
function base(count, parent){
this.id = parent+"_base"+count;
this.parent = parent;
this.children = [];
this.remove = function (){
$('#'+this.id).remove();
};
this.render = baseRenderFactory(this);
this.addChild = addChildFactory(this);
this.getBaseButtons = function(){
var addAttributeButton = new $("<button>+ Attribute</button>").button();
var addTextButton = new $("<button>+ Text</button>").button();
return [addAttributeButton, addTextButton];
};
}
The problem now is. When i debug the code and set a breakpoint within the "render" function of the root-object. Then i can see, that "this" is not the root but the "base" object. And i cannot figure out why it is like that because the "root" object is the owner of this function, and my base has an own render function which is not called directly there.
So even the "this" in the line
$.each(this.children,function(i,obj){
Refers to the "base" object. But the "this" is inside the "root" object...
Hope you can help me :-)
EDIT:
The code to let it run:
var test = new templateRoot();
test.addBase();
test.render();
EDIT 2:
"that" in "addBaseFactory" refers to the correct "base" object.
I found your explanation pretty confusing, so I may have misinterpreted what you're trying to do, but I think you expect this within your nested functions to the same object as the this in the outer templateRoot() function. That's not how this works in JavaScript. Nested functions don't inherit the same this as the containing function - each function has its own this object that is set depending on how the function is called.
Here's one possible solution, which uses the fact that nested functions can see variables from their containing function(s):
function templateRoot(){
var self = this; // save a reference to this for use in nested functions
this.id = "root";
this.parent = null;
this.children = [];
this.editable = true; // bla
this.render = function(){
$.each(self.children,function(i,obj){
self.children[i].render();
var baseButtons = this.getBaseButtons();
$('#'+self.id).append(baseButtons);
});
};
this.addBase = addBaseFactory(this);
};
A detailed explanation about how this works in JS can be found at MDN.
Wouldn't this render its childerens children, since jquery would send each child as this?
this.render = function(){
$.each(this.children,function(i,obj){
this.children[i].render();
var baseButtons = this.getBaseButtons();
$('#'+this.id).append(baseButtons);
});
};
Btw in what scope is addBaseFactory called? Because I think the "this" in the base, will refer to that scope.

Calling javascript method from from inside object

I am struggling with methods in JavaScript.
obj = function(){
this.getMail = function getMail (){
}
//Here I would like to run the get mail once but this.getMail() or getMail() wont work
}
var mail = new obj();
mail.getMail();
How do I make the method in a way that I can run it both inside the object and from the outside
Thanks
When you define the function use the name just once, like this:
obj = function(){
this.getMail = function(){
alert("bob");
}
}
Now you can use this.getMail() in there, you can see a working example here.
here you go:
var obj = function() {
function getMail() {
alert('hai!');
}
this.getMail = getMail;
//Here I would like to run the get mail once but this.getMail() or getMail() wont work
getMail();
}
var mail = new obj();
mail.getMail();
Building a robust definition for your object is recommended. Build a prototype for it, then if you ever need two or more, you can make instances of them. I show below how to build a prototype, add methods that call eachother, and how to instantiate the object.
obj = function () {} //define the empty object
obj.prototype.getMail = function () {
//this is a function on new instances of that object
//whatever code you like
return mail;
}
obj.prototype.otherMethod = function () {
//this is another function that can access obj.getMail via 'this'
this.getMail();
}
var test = new obj; //make a new instance
test.getMail(); //call the first method
test.otherMethod(); //call the second method (that has access to the first)

Categories

Resources