Object modified in the function is not being modified outside the function - javascript

I'm building a code to parse some JSON details received from the server into a javascript object. The object has many objects inside it.
Then I have another function to create HTML element and apply that object's values (using for - in loop) into HTML tags' "innerHTML".
I have included the code i use below,
// This one is executed on the 'onLoad' event.
function requestDriverListings() {
**//This object stores the received object from server.**
var drivers = {};
// ***This function requests details from the server and the function in the arguments is executed once the details are received.***
sendUserData ({}, "request driver.php", function (request) {
listDrivers(request,drivers); console.log(drivers); displayDrivers(drivers);});
}
This one is the function to create a HTML Element and stores the received data in it and the use JSON.parse() to parse them into a Object.
The driver parameter is the Object passed in the above code.
request parameter has no effect on this problem. (It is the XHR responseText.)
function listDrivers (request,driver) {
var response = document.createElement("html");
response.innerHTML = request;
driver = response.querySelector("#drivers").innerHTML;
var stripComma = driver.lastIndexOf(",");
driver = JSON.parse(driver.substring(0,stripComma) +"}");
}
Here is the displayDrivers function.
drivers Object is passed into driveParsed in the first function.
requestAPage() is a function to request the displaying element from the server. the function in it's arguments is the function to apply the Objects details into the HTML innerHTML.
function displayDrivers (driveParsed) {
var driverElement = document.createElement("div");
driverElement.id = "driverElement";
driverElement.style.display = "none";
document.getElementById("driverContainer").appendChild(driverElement);
requestAPage("Drivers.html", "drivers", "driverElement", function() { selectDrivers();});
var selectDrivers = function () {
for (var x=0; x<=Object.keys(driveParsed).length; x++) {
var driverParsed = driveParsed[x];
setDriversDetails(driveParsed,x);
var element = createAElement( "div", {"margin-top": "10px;"});
element.id = driveParsed.name;
element.className = "container border";
element.innerHTML = driverElement.innerHTML;
document.getElementById("driverContainer").appendChild(element);
}
};
}
================================================================
My problem is this displayDrivers() is not getting the modified drivers Object.
Please help me to solve this problem. Sorry for the long description.

One problem is that inside listDrivers you assign a new value to the driver variable (which is an argument). This means the original variable, drivers, that was passed to the function as second argument, is disconnected from the local function variable driver: they are now two distinct, unrelated objects.
If you want the drivers variable to get a value from calling the function, then let that be the return value of the function, so you would call it like this:
sendUserData ({}, "request driver.php", function (request) {
var drivers = listDrivers(request); // <-----
console.log(drivers);
displayDrivers(drivers);
});
Then the listDrivers function would look like this:
function listDrivers (request) { // <--- only one argument
// declare new variable:
var driver = response.querySelector("#drivers").innerHTML;
// ... rest of your code comes here ...
// ... and finally:
return driver; // <---- return it
}

#trincot beat me to it and his answer is better. I'll leave this up anyway though.
Try doing this in requestDriverListings:
function requestDriverListings() {
var drivers = {};
sendUserData ({}, "request driver.php", function (request) {
var updatedDrivers = listDrivers(request,drivers);
console.log(drivers);
displayDrivers(updatedDrivers);});
}
And this in listDrivers:
function listDrivers (request,driver) {
var response = document.createElement("html");
response.innerHTML = request;
driver = response.querySelector("#drivers").innerHTML;
var stripComma = driver.lastIndexOf(",");
driver = JSON.parse(driver.substring(0,stripComma) +"}");
return driver;
}

Related

javascript, passing parameters to a callback inside a closure that is inside a function

I'm stuck with a problem related to db.transaction().objectStore.onsuccess
i need to get back the data to create a table with the results.
As first test, i try to return data from the call after the cursor has been read completely:
function readAll() {
var resultData=[];
var objectStore = db.transaction("employee").objectStore("employee");
objectStore.openCursor().onsuccess = function(event, args) {
var cursor = event.target.result;
if (cursor){
resultData.push(cursor.value);
cursor.continue();
}else{
return resultData;
}
};
}
but this doesn't work because the asynchronous nature of the indexedDB
so, after some thinking i try to use a callback...
function readAll(callBackFunction) {
var resultData=[];
var objectStore = db.transaction("employee").objectStore("employee");
objectStore.openCursor().onsuccess = function(event, args) {
var cursor = event.target.result;
if (cursor){
resultData.push(cursor.value);
cursor.continue();
}else{
callBackFunction;
}
};
}
this seem partially work because the callback will be called but I'm not able to pass parameters to the callback function because parameters array is empty inside the onsuccess=function() (as i can understand parameters are bind to readAll function) and I'm not able to pass it inside the onsuccess.
So how can i pass parameters to callback?
There is another option different from the callback?
thank you
UPDATE
My problem is that i need to pass more parameters other than the result, like "table_id", "header" etc. so i need to pass some parameters to readAll and pass those parameters to callback, something like:
readAll(callBackFunction, "table_id", "header_array")
I've already tested below solution that doesn't work:
function readAll(callBackFunction) {
var resultData=[];
var objectStore = db.transaction("employee").objectStore("employee");
objectStore.openCursor().onsuccess = function(event, args) {
var cursor = event.target.result;
if (cursor){
resultData.push(cursor.value);
cursor.continue();
}else{
callBackFunction(parameters[1], parameters[2], resultData);
}
};
}
readAll(createTable, 'table_id', ['username', 'email']);
the problem is that the parameters array is empty inside the closure
UPDATE 2
arguments array is empty inside the closure but is ok outside. If i move the callback outside the closure, I've have parameters but not data..
UPDATE 3
Also adding all parameters to function seem not working.
function readAll(callback, header, idName, classToAdd, resultData) {
var resultData=[];
var objectStore = db.transaction("employee").objectStore("employee");
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if (cursor){
resultData.push(cursor.value);
//alert("Name for id " + cursor.key + " is " + cursor.value.name + ", Age: " + cursor.value.age + ", Email: " + cursor.value.email);
cursor.continue();
}else{
//HERE ALL ARGUMENTS ARE EMPTY BUT resultData Exists!
callback(arguments[1], arguments[2], arguments[3], arguments[4], resultData);
}
};
//HERE ALL ARGUMENTS EXISTS EXCEPT resultData!
callback(arguments[1], arguments[2], arguments[3], arguments[4], resultData);
}
You could just invoke the function like
callBackFunction(resultData);
so that the function you passed receive the results. In the function declaration you should have such a parameter:
function callbackFunction(results) {
//create the table
}
You would pass it to readAll() like
readAll(callbackFunction);
EDIT:
According to your edit.
You have to add extra parameters to your function declaration
function readAll(callBackFunction, table_id, data) {
// ... code
callBackFunction(table_id, data, resultData);
}
Then you can declare 2 more parameters in your createTable function and they will receive "table_id" and "data".
after some time I'm back to this problem and find a solution that work.
The problem is that I initialize the objectStore in a single call.
var objectStore = db.transaction("employee").objectStore("employee");
if I divide this call in two different pieces:
var transaction = db.transaction("employee");
var objectStore = transaction.objectStore("employee");
everything work as expected.

JavaScript Object is set but is null when accessed

I have the following object that constructs a session variable:
var sessionObject = function (key) {
this._key = key;
this._content;
this.set = function (v) {
this.setLocal(v);
$.post('/Program/SetVariable',
{ key: this._key, value: v }, function (data) {
});
};
this.get = function (callback) {
var setterCallback = this.setLocal;
$.get('/Program/GetVariable',
{ key: this._key }, function (data) {
setterCallback(data);
}).done(function () {
callback();
});
};
this.setLocal = function (v) {
this._content = v;
};
this.getLocal = function () {
return this._content;
};
}
And my C# in the controller is as follows:
public ActionResult SetVariable(string key, string value)
{
Session[key] = value;
return this.Json(new { success = true });
}
public ActionResult GetVariable(string key)
{
return this.Json(Session[key], JsonRequestBehavior.AllowGet);
}
I create a new session object every time the page is loaded, which references items in the session located on the server. When the session is set with the set() function, _content is set correctly and is able to be accessed publicly through item.getLocal() (either in the browser console or in code).
When I revisit the page and the session object referring to said item is already created, when I run the item.get() function it accesses the session variable and sets it to the _content object, I know this because I can do a console.log(this._content) in the setLocal() function which shows that the variable has been set correctly. But when I wish to access the content of the session object via either this.getLocal() or item._content while through the browser console or other lines of the code I get undefined returned to me.
So to illuminate the process some more this is what I do on a reload where there is already data in the session:
var item = new sessionObject("item");
item.get(printData);
function printData() {
$("printbox").append(item.getLocal());
}
This does not print anything.
Is there a reason I can not access this item's content unless it is specifically set by the item.set function?
Because you do this:
var setterCallback = this.setLocal;
and call it like so:
setterCallback(data);
You have lost the context of your sessionObject instance, so the this inside the setLocal function is no longer your object instance but the global window object.
You can do two things to correct this, save a reference to this instead of saving a reference to the function and call setLocal from that reference
var that = this;
/.../
that.setLocal(data);
or you can bind object instance when you save the setLocal reference
var setterCallack = this.setLocal.bind(this);

How to return array

I am using the below function to load xml and then return the array with values.
But when i call it in another function it gives error "arrXML is undefined".
function readXML() {
// create an array object
var arrXML = new Array();
//create XML DOM object
var docXML = Sys.OleObject("Msxml2.DOMDocument.6.0");
// load xml
docXML.load("C:\\Users\\ankit\\Desktop\\read.xml");
// search nodes with 'config' tag
var Nodes = docXML.selectNodes("//config");
for (i = 0; i < Nodes.length; i++){
var ChildNodes = Nodes.item(i);
arrXML[i] = Nodes(i).childNodes(0).text +":"+Nodes(i).childNodes(1).text;
}
// return array of XML elements
return arrXML;
}
function getvalues() {
log.message(arrXML[1]); // this line gives error
}
arrXML is local to the function readXML because you declared it with the var keyword inside that block. getValues has no idea it exists (because it no longer does).
Your options are to make the variable global (which you should be careful with)
vinu = {}; // vinu is global namespace containing the array
function readXML() {
vinu.arrXML = [];
// ...
return vinu.arrXML; // This might not even be necessary in this case
}
function getvalues() {
log.message(vinu.arrXML[1]);
}
... or to pass the variable to the function when you call it.
function getvalues(arg) {
log.message(arg[arrXML[1]]);
return arg; // This function can't change the original variable, so use the return if need-be
}
// Somewhere that has access to the actual "arrXML"
getvalues(arrXML);
... or use a closure.

JavaScript OOP : running two instances of a method within a single Object simultaneously

So, I have an object Async that creates a request for (in this case) a JSON object from github.
There is a method Async.createList that creates a list of all instances of a specific attribute from the github JSON object. It works just fine when Async.createList is called once, but I want to be able to create multiple lists from different target attributes from the same request, and this is where it fails.
Ideally, the lists would be appended to the Async.lists object so that they can be used outside of the Async object. Right now, when I call Async.createList multiple times, only the last call appends to Async.lists.
function Async(address) {
this.req = new XMLHttpRequest();
this.address = address
}
Async.prototype = {
lists : {},
create : function(callback) {
var self = this;
this.req.open('GET', this.address, true);
this.req.onreadystatechange = function(e) {
if (this.readyState == 4) {
if (this.status == 200) {
dump(this.responseText);
if (callback != null) callback()
} else {
dump("COULD NOT LOAD \n");
}
}
}
this.req.send(null);
},
response : function(json) {
return json == true ? JSON.parse(this.req.responseText) : this.req.responseText
},
createList : function(target) {
var self = this
var bits = []
this.req.onload = function(){
var list = self.response(true)
for(obj in list){
bits.push(self.response(true)[obj][target])
}
self.lists[target] = bits
}
},
}
I am creating the object and calling the methods like this:
var github = new Async("https://api.github.com/users/john/repos")
github.create();
github.createList("name");
github.createList("id");
And then trying:
github.lists
You are re-assigning the function for this.req.onload every time you call github.createList.
i understand you want to do things after the request is loaded using req.onload, but you are assigning a new function everytime, so the last assigned function will be called.
You need to remove the onload function within Async.createList
Call github.createList("name"); only after the request is loaded as follows
var github = new Async("https://api.github.com/users/john/repos")
github.create();
github.req.onload = function () {
github.createList("name");
github.createList("id");
}
The answer is painfully simple. All I needed to do was get rid of the onload function within Async.createList and simple call Async.createList in the callback of Async.create
createList : function(target) {
var self = this
var bits = []
var list = self.response(true)
for(obj in list){
bits.push(self.response(true)[obj][target])
}
self.lists[target] = bits
},
Using this to instantiate:
var github = new Async("https://api.github.com/users/john/repos")
github.create(callback);
function callback(){
github.createList("name");
github.createList("id");
}

Set Method doesn't set the Member though being called with valid argument

im getting frustrated because of this piece of code:
function Model(){
this.GetAjaxData = function(){
//private Member to be returned
var res;
function setRes(newVal){
res = newVal;
alert(newVal); // to verify its really being called
}
// calls a Ajax-Service(1st param) with the given arguments(2nd param),
// the 3rd param is a function with gets called back, commiting the
// output of the Ajax-Service as arguments for the called function
tw.coach.callService(
"GetServerTime",
"<inputs><variable name='input1' type='String'>lala</variable></inputs>",
function(arg){ setRes(arg['Result']); }
);
return res;
};
}
Now, what happens is, once an instance of model has been initialized and the method is being called like:
var _model = new Model();
document.getElementById("myDiv").innerHTML = _model.GetAjaxData();
the alert pops up with the expected data (the Ajax Service simply returns {Result: this came via Ajax.}) but myDiv constains undefined. This tells me that the setRes() is called correctly but it just doesn't set the value of res.
And I have no idea why.
Change your approach taking into consideration async nature of AJAX requests:
function Model() {
this.GetAjaxData = function(callback) {
var data = "<inputs><variable name='input1' type='String'>lala</variable></inputs>";
tw.coach.callService("GetServerTime", data, function(arg) {
callback(arg['Result']);
});
};
}​
var _model = new Model();
_model.GetAjaxData(function(res) {
document.getElementById("myDiv").innerHTML = res;
});

Categories