Access object property within a callback - javascript

I wrote the following code:
var Request = require('./request');
function Treasure(id) {
Treasure.prototype.valid = false;
Treasure.prototype.id = id;
Treasure.prototype.contentLength = 0;
Treasure.prototype.title = null;
Treasure.prototype.seller = null;
Treasure.prototype.buyer = null;
Treasure.prototype.cost = 0;
}
Treasure.prototype.loadData = function() {
EpvpRequest.treasureRequest(Treasure.prototype.id, function(data) {
if (data.valid) {
Treasure.prototype.valid = data.valid;
Treasure.prototype.contentLength = data.contentLength;
Treasure.prototype.title = data.title;
Treasure.prototype.seller = data.seller;
Treasure.prototype.buyer = data.buyer;
Treasure.prototype.cost = data.cost;
}
});
}
module.exports = Treasure;
Please don't hit me, I just started learning javascript.
I want ot access the properties of "Treasure"; but I can't use this, because I have a callback in the loadData function and this would refer to the function which called the callback - is that correct?
But it seems that I can't access the properties the way I tried with Treasure.prototype.property.
What is the correct way to to this?

First of all, you should be assigning instance variables in the constructor instead of assiginng to the prototype. The prototype is for methods and other things that will be shared by all Treasure instances.
function Treasure(id) {
this.valid = false;
this.id = id;
this.contentLength = 0;
this.title = null;
this.seller = null;
this.buyer = null;
this.cost = 0;
}
As for your problem with this inside callbacks, the usual workaround is to store the value of this in a regular variable and then use that variable inside the callback.
Treasure.prototype.loadData = function() {
// Nothing special about "that"
// Its just a regular variable.
var that = this;
EpvpRequest.treasureRequest(that.id, function(data) {
if (data.valid) {
that.valid = data.valid;
that.contentLength = data.contentLength;
that.title = data.title;
that.seller = data.seller;
that.buyer = data.buyer;
that.cost = data.cost;
}
});
}
Since this pattern comes up very often, some people choose to always use the same name for the "this-storage" variable. Some of the more popular names are self and that.

Related

How to overwrite default value from properties of this object with call or apply method in JS

I've started learning call, apply and bind and now i want to use it but have some problems:
I have a function:
let addTableRow = function() {
let template = HtmlTemplatesTelephony.ks.renderTableRow;
this.id = "";
this.creationDate = "";
this.address = "";
this.numberOfUser = "";
this.accessExisting = true;
$(DOM.tableBodyContainer).append(template(this));
};
I declared the this properties as default values
Here i invoke the function either with .call() or without:
let updateTable = function() {
let locations = userData().locations;
if(locations.length > 0) {
for(let location of locations) {
UIController.addLocation.call(location);
}
} else {
UIController.addLocation();
}
};
My idea was to use the 'this' values in the 'addTableRow' as default values in case of invoking the function without .call(). And when calling it with .call() I want to overwrite the 'this' default values. But exactly the opposite happens.
I know I could pass the object as parameter and set default object, but is there an other way to do it with .call()? Or is it the wrong use case for .call()?
Thanks for help!
***** UPDATE ******
Sorry, it is written in module pattern and i forgot to mention that the function 'addTableRow' is called 'addLoaction' in the return object. Here's some more code:
My UI controller:
let UIController = (function() {
let DOM = {
tableHeadContainer: $('thead'),
tableBodyContainer: $('tbody'),
inputNumberLocations: $('#numberLocations'),
inputAddress: $('.js-location-address'),
inputUser: $('.js-location-user'),
inputVpn: $('.js-location-vpn'),
btnDeleteLocation: $('.js-delete-location'),
};
let addTableRow = function() {
let template = HtmlTemplatesTelephony.ks.renderTableRow;
this.id = "";
this.creationDate = "";
this.address = "";
this.numberOfUser = "";
this.accessExisting = true;
$(DOM.tableBodyContainer).append(template(this));
};
return {
getDOM: DOM,
addLocation: addTableRow,
removeLocation: removeTableRow
}
})();
And my main controller:
let Controller = (function(dataController, UIController) {
let updateTable = function() {
let locations = userData().locations; // locations has the same properties as in function 'addTableTow'
if(locations.length > 0) {
for(let location of locations) {
UIController.addLocation.call(location);
}
} else {
UIController.addLocation();
}
};
return {
init: function() {
setupEventListeners();
updateTable();
},
}
})(dataController, UIController);
I hope it's more clear now.
When you .call(obj), you are starting your function with this being equal to that object. When you say this.id = "", you are overriding the id that you already had.
This may be a solution to your problem:
if (!this.id) {
this.id = "";
}
if (!this.property) {
this.property = "default";
}
// etc.

private object not setting data

Hi I'm trying to implement a LinkedList in Javascript. When i assign a value to my node it doesn't seem to store it when I use my getter. For example:
var Node =function() {
var _data;
var _next ={};
var that = this;
that.getData = function() {
return _data;
};
that.setData = function(data) {
that._data = data;
};
that.getNext = function() {
return _next;
};
that.setNext = function(next) {
that._next = next;
};
return that;
};
Will not work with:
var nodeObj = new Node();
nodeObj.setData("hello");
console.log(nodeObj.getData());
_data is not the same as that._data, you must do this:
that.getData = function() {
return that._data;
};
OR you could do this instead:
that.setData = function(data) {
_data = data;
};
the benefit of the second approach being that you're simulating a private variable (because you cannot do nodeObj._data in the second case but you can in the first)
also var that = this; is unnecessary, you can simply do this._data in this case.
For your case here, you can assume that if you're calling a function like yourObject.someFunction(), then within someFunction the value of this equals yourObject. (And this isn't always true in javascript but since you're starting off you should think about it this way for now. If you pass a function to another function as a variable and then call it then this wouldn't be the case).

Make json from array of objects javascript

I have a javascript object with a lot of attributes and methods, I want it to be sent to a php file. For this, I want to transform it to Json data.
But I just can`t understand how should I use json.stringify to do this, because of the complex object's class.
The objects looks like this. I have an array of objects that I have to sent over ajax.
Also, this class has array of other objects as attributes, and a bunch of other methods.
var PhotoFile = function(clientFileHandle){
PhotoFile.count = PhotoFile.count + 1;
this.specificClass = "no-" + PhotoFile.count;
this.checkbox = null;
this.attributes = [];
this.file = clientFileHandle;
this.fileExtension = null;
//meta data
this.meta = null;
this.orientation = null;
this.oDateTime = null;
this.maxWidth = 150;
this.maxHeight = 100;
//raw data
this.imgData = null;
this.imgDataWidth = null;
this.imgDataHeight = null;
this.checkSum1 = null;
this.checkSum2 = null;
//DOM stuff
this.domElement = null;
this.imgElement = null;
this.loadProgressBar = null;
this.uploadProgressBar = null;
this.imageContainer = null;
this.attributeContainer = null;
this.indexInGlobalArray = -1;
//flags
this.metaLoaded = false;
this.startedLoading = false;
this.finishedLoading = false;
this.needsUploading = true;
this.imageDisplayed = false;
//listeners
this.onFinishedLoading = function () {};
this.onFinishedUploading = function () {console.log('Called default end '+this.file.name)};
..... plus other methods.
}
You could create a function on your object that returns a serializable representation of your object.
E.g.
function SomeObject() {
this.serializeThis = 'serializeThis';
this.dontSerializeThis = 'dontSerializeThis';
}
SomeObject.prototype.toSerializable = function () {
//You can use a generic solution like below
return subsetOf(this, ['serializeThis']);
//Or a hard-coded version
// return { serializeThis: this.serializeThis };
};
//The generic property extraction algorithm would need to be more complex
//to deep-filter objects.
function subsetOf(obj, props) {
return (props || []).reduce(function (subset, prop) {
subset[prop] = obj[prop];
return subset;
}, {});
}
var o = new SomeObject();
JSON.stringify(o.toSerializable()); //{"serializeThis":"serializeThis"}
Note that using a generic property extractor algorithm would force you to leak implementation details and therefore, violate encapsulation so although it might be shorter to implement a solution using this method, it might not be the best way in some cases.
However, one thing that can usually be done to limit internals leakage is to implement property getters.

How to get Javascript class fields and functions

Is there any way to get functions and fields from JavaScript class without initializing an object of that class?
var SimpleClass = function() {
this.type = 'singleClassType';
this.getType = function() {
var self = this;
return self.type;
}
}
I want to get type field (which is like static).
I can do something like this, but I really don`t want to use prototype of class:
SimpleClass.prototype.type = 'customName'
Here is the code I use:
var Class1 = function(id) {
this.id = id;
}
Class1.prototype.type = 'class1';
var Class2 = function(id) {
this.id = id;
}
Class2.prototype.type = 'class2';
var Class3 = function(id) {
this.id = id;
}
Class3.prototype.type = 'class3';
var Class4 = function(id) {
this.id = id;
}
Class4.prototype.type = 'class4';
var xml = {},
xmlText = '';
$(document).ready(function(){
generateObjects();
});
function generateObjects() {
for(var i=1;i<5;i++){
if(typeof eval('Class'+i).prototype.getHtml === 'undefined'){
$.ajax({
dataType: 'xml',
url: 'file.xml',
async: false,
success: function(data){
xmlText = data;
addClassData();
}
});
function addClassData(){
xml['"'+eval('Class'+i).prototype.type+'"'] = xmlText;
}
eval('Class'+i).prototype.getHtml = function(){
var self = this;
return xml['"'+self.type+'"'];
}
}
var kl = eval('Class'+i),
obj = new kl(i);
console.log(obj.getHtml());
}
}
Is there any way to get functions and fields from JavaScript class without initializing an object of that class?
No. Unless you decompile the function, parse the JS code and look for property assignments.
I can do something like this, but I really don't want to use prototype of class:
There's nothing wrong with using the prototype if this field is supposed to be shared amongst all instances of the class.
If by "static" you mean that it's rather a class member than an instance member, you can put properties directly on the constructor as well:
var SimpleClass = function() {
this.getType = function() {
return SimpleClass.type;
// alternatively, something like `this.constructor.type`
// but only if you understand when this works and when not
}
}
SimpleClass.type = 'singleClassType';
Accessing the property/field like this:
var SimpleClass = function(){
this.type = 'singleClassType';
this.getType = function(){
var self = this;
return self.type;
}
}
SimpleClass["type"] = 'customName';
alert(SimpleClass["type"]);
should work too. Have a look at this MDN article - property accessors.
Have a look at this MDN article - Working with objects for more thorough information about OOP concepts using JavaScript in order to avoid the problem that #PaulS pointed out in his comment.

Javascript module pattern, nested functions, and sub modules

I am trying to wrap my head around javascript modules, but I'm unsure how to split up a module into further sub modules. I have read that nested functions are not really a great idea, due to performance, so how do I break up a function in a module? For example, lets say I have the following module:
var Editor = {};
Editor.build = (function () {
var x = 100;
return {
bigFunction: function () {
// This is where I need to define a couple smaller functions
// should I create a new module for bigFunction? If so, should it be nested in Editor.build somehow?
}
};
})();
bigFunction is only related to Editor.build. Should I attach the smaller functions that make up bigFunction to the prototype bigFunction object? I'm not even sure if that would make sense.
var Editor = {};
Editor.build = (function () {
var x = 100;
return {
bigFunction: function () {
bigFunction.smallFunction();
bigFunction.prototype.smallFunction = function(){ /*do something */ };
// not sure if this even makes sense
}
};
})();
Can someone please throw me in the right direction here? There is so much misleading information online, and would just like a definite guide on how to deal with this sort of modularization.
Thank you.
Here is a snippet I use to make names for an input:
var dynamicCounter = 0;
//custom dropdown names
var createContainerNames = function () {
function Names() {
this.id = "Tasks_" + dynamicCounter + "__ContainerId";
this.name = "Tasks[" + dynamicCounter + "].ContainerId";
this.parent = "task" + dynamicCounter + "Container";
}
Names.prototype = { constructor: Names };
return function () { return new Names(); };
} ();
And then I use it:
var createdNames = createContainerNames();
var createdId = createdNames.id;
dynamicCounter++;
var differentNames = createContainerNames();
var differentId = differentNames.id;
Another approach would be to do this:
var NameModule = function(){
//"private" namemodule variables
var priv1 = "Hello";
//"private namemodule methods
function privMethod1(){
//TODO: implement
}
//"public namemodule variables
var pub1 = "Welcome";
//"public" namemodule methods
function PubMethod(){
//TODO: pub
}
return {
pub1 : pub1,
PubMethod: PubMethod
};
and then to use it
var myPubMethod = new NameModule();
myPubMethod.PubMethod();
var pubVar = myPubMethod.pub1;
EDIT
You could also take this approach:
var mod = function(){
this.modArray = [];
};
mod.prototype = {
//private variables
modId: null,
//public method
AddToArray: function (obj) {
this.modArray.push(obj);
}
}

Categories

Resources