Can't set scoped variable in $.post callback - javascript

I have the following type of structure:
(function(){
var objects = [];
$('button.one').on('click', function(){
fetchObjects = function(objects) {
$.post("/fetchObjects")
.done(function(data){
objects = data;
console.log(objects.length);
});
}
fetchObjects(objects)
});
$('button.two').on('click', function(){
console.log(objects.length);
});
})();
You can see I have a variable objects that is local to this function. Initially its empty. When I click button.one I wish to populate objects with the returned value from some ajax request. It appears to work, however when clicking button.two, the objects variable is still an empty array.
Why isn't objects available in the jQuery callback?
I've also tried this approach but with the same results:
function callback(data) {
facilities = data
}
$.post("/fetchObjects")
.done(function(data){
callback(data);
});
What am I missing here? Please don't tell me to make "objects" global.

I don't know why you're passing objects as parameter. The following should work fine I think. Please let me know if you're trying to achieve something else.
(function(){
var objects = [];
$('button.one').on('click', function(){
fetchObjects = function() {
$.post("/fetchObjects")
.done(function(data){
objects = data;
console.log(objects.length);
});
}
fetchObjects()
});
$('button.two').on('click', function(){
console.log(objects.length);
});
})();

Let's simplify the code a bit. You have essentially this:
var objects = [];
fetchObjects = function(innerObjects) {
var data = ['a','b'];
innerObjects = data;
console.log(innerObjects.length);
};
fetchObjects(objects);
console.log(objects);
(I've changed the other objects variable's name just for clarity; the issue is the same even if it had the same name.)
When you call the function, innerObjects contains a reference to objects so modifying it would change the original array as well. But when you do
innerObjects = data;
now instead of modifying the array you're replacing the reference with something else. innerObjects "points" to data instead of objects and the original variable remains unchanged.
To make it work you'd need to loop through the data array (assuming it'll always be an array) and assign the contents to the objects reference one by one. This way you'll keep the original reference and modify the original array.
var objects = [];
fetchObjects = function(innerObjects) {
var data = ['a','b'];
for( var i = 0; i < data.length; i++ ) {
innerObjects[i] = data[i];
}
console.log(innerObjects.length);
};
fetchObjects(objects);
console.log(objects);
Or, in your actual code:
(function(){
var objects = [];
$('button.one').on('click', function(){
fetchObjects = function(objects) {
$.post("/fetchObjects")
.done(function(data){
for( var i = 0; i < data.length; i++ ) {
objects[i] = data[i];
}
console.log(objects.length);
});
}
fetchObjects(objects)
});
$('button.two').on('click', function(){
console.log(objects.length);
});
})();

Related

How to access specific properties in a multiple objects using JS

Here is my object:
$scope.info = [];
$scope.info = [{"name":"kanye","size":"","folder":"Folder"},{"name":"west","size":"","folder":"Folder"}]
$scope.infoObj = $scope.info.name;
console.log($scope.infoObj);
This return me Undefined. The response should be like this:
[{"name":kanye},{"name":west}]
But how to access the specific properties from a multiple object using angularJS or jquery/js?
This should solve the problem:
$scope.infoObj = $scope.info.map(function(obj){
var x = {};
x['name'] = obj['name'];
return x;
})
for ES6, it can be simplified to:
$scope.infoObj = $scope.info.map(x => ({name:x['name']}))
You can actually do a little bit of refactoring to make your code a little cleaner and more readable. Instead of setting your info value twice, set it once, and add the objects in each line after.
Like this:
$scope.info = [];
$scope.info.push({
"name":"kanye",
"size":"",
"folder":"Folder"
});
$scope.info.push({
"name":"west",
"size":"",
"folder":"Folder"
});
See how clean that is? Now it should be fairly obvious that info is an Array of objects, so doing $scope.info.name won't work. What I would recommend is creating a lookup function that can help grab a list based on the key you provide it.
Something like this:
function lookup(key) {
var result = [];
for (var i = 0; i < $scope.info.length; i++) {
var object = {};
object[key] = $scope.info[i][key];
result.push(object);
}
return result;
}
And then call it like this:
$scope.infoObj = lookup('name');
console.log($scope.infoObj);

How can I put the results in an array after use each in javascript?

Hi I have this function:
changeTarea: function() {
var self = this;
$("#select_tarea_id").change(function() {
var id_tarea = $("#select_tarea_id").val();
$.each(self.objTareasFlot, function(index,value) {
for(var i = 0; i < value.length; i++) {
if(value[i].Id == id_tarea) {
self.objTareasFlotFinal['id']=value[i].Id;
self.objTareasFlotFinal['id_pro']=value[i].Id_proyecto;
self.objTareasFlotFinal['tarea']=value[i].nombre_tarea;
self.objTareasFlotFinal['porcentaje']=value[i].porcentaje;
console.info(self.objTareasFlotFinal);
}
}
});
});
}
And the function print :
But I need the 3 results in one array
for example :
How can I do that with that function? Sorry for my english I did try to explain of the better way
You can declare an array and push populated object into it. Something like this:
changeTarea: function(){
var self = this;
var container[];
$("#select_tarea_id").change(function() {
var id_tarea = $("#select_tarea_id").val();
$.each(self.objTareasFlot, function(index,value) {
for(var i = 0; i < value.length; i++){
if(value[i].Id == id_tarea){
self.objTareasFlotFinal['id']=value[i].Id;
self.objTareasFlotFinal['id_pro']=value[i].Id_proyecto;
self.objTareasFlotFinal['tarea']=value[i].nombre_tarea;
self.objTareasFlotFinal['porcentaje']=value[i].porcentaje;
console.info(self.objTareasFlotFinal);
container.push(self.objTareasFlotFinal);
}
}
});
});},
Create an array variable var result = []; inside your function.
Within your loop push() the objects into it;
results.push(self.objTareasFlotFinal);
var newArray = [];
self.objTareasFlotFinal['id']=value[i].Id;
self.objTareasFlotFinal['id_pro']=value[i].Id_proyecto;
self.objTareasFlotFinal['tarea']=value[i].nombre_tarea;
self.objTareasFlotFinal['porcentaje']=value[i].porcentaje;
newArray.push(self.objTareasFlotFinal);
// console.log should show the results
console.log(newArray);
If this array is meant to be global and accessible outside the function, you might want to define newArray outside the function first and remove the var from it within the function.
Then every time somebody runs the function, a new object is added to the array.
Alternatively, you could just return the array as the final value:
var newArray = [];
self.objTareasFlotFinal['id']=value[i].Id;
self.objTareasFlotFinal['id_pro']=value[i].Id_proyecto;
self.objTareasFlotFinal['tarea']=value[i].nombre_tarea;
self.objTareasFlotFinal['porcentaje']=value[i].porcentaje;
newArray.push(self.objTareasFlotFinal);
return newArray;

Creating an object from html elements using JavaScript and jQuery

I want to create an object from html elements using JavaScript and jQuery.
The object i want to create is
{
array:[{infraStructureType: 'value', hostId: 'value'}, {infraStructureType: 'value', hostId: 'value'}]
}
So my code to create above object is
var obj = {}, dataObj = {compareESX: []};
$('.checkBox:checked').each(function () {
obj.infraStructureType = $(event.target).attr('hostId');
obj.hostId = $(event.target).attr('infrastructureType');
console.log(obj);
dataObj.compareESX.push(obj);
console.log(dataObj);
});
In above code "console.log(obj)" gives correct output but, when i push it in array "dataObj.compareESX"
Only information of last 'obj' is getting pushed number of times the each loop executes.
JS uses Call by reference method.So when update obj it changes all values. You need to do deep copy.Use this
dataObj.compareESX.push(JSON.parse(JSON.stringify(obj)));
Try this: FIDDLE
We need to define the obj again to clear the previous values.
var dataObj = {compareESX: []};
$('.checkBox:checked').each(function (e) {
var obj = {};
obj.infraStructureType = $(this).attr('hostId');
obj.hostId = $(this).attr('infrastructureType');
//console.log(obj);
dataObj.compareESX.push(obj);
//console.log(dataObj);
});
console.log(dataObj);
You have to put your object definitions var obj = {} inside your each loop. Right now you are using the same object for every entry in the loop. Instead, you should create a new object for every checkbox over which you loop.
var dataObj = {compareESX: []};
$('.checkBox:checked').each(function () {
var obj = {};
obj.infraStructureType = $(event.target).attr('hostId');
obj.hostId = $(event.target).attr('infrastructureType');
console.log(obj);
dataObj.compareESX.push(obj);
console.log(dataObj);
});

Javascript class with jQuery and JSON

i'm creating a function that i wanna use as class on javascript.
My function, will call an JSON page create with php parse json, and set the vars, but it doesen't work.
May you can give me some hints?
Here's the code, thx in advance:
function SiteParams(){
$.getJSON("parse/parametri.php",function(data){
$.each(data,function(index,value){
this.NomeSito = value.nomesito;
this.URLSito = value.urlsito;
this.EmailAutore = value.email;
this.NomeAutore = value.nomeautore;
});
});
}
var website = new SiteParams();
function ModuleBase(){
$("<div/>",{id:"title", text:website.NomeSito}).appendTo("#main");
}
This is a good place to use $.Deferred
function SiteParams(){
// create a private deferred, and expose the promise:
var d = new $.Deferred();
this.load = d.promise();
var that = this;
$.getJSON("parse/parametri.php", function(data) {
// your $.each only used one value anyway
var value = data[0];
// copy the data across
that.NomeSito = value.nomesito;
that.URLSito = value.urlsito;
that.EmailAutore = value.email;
that.NomeAutore = value.nomeautore;
// resolve the promise
d.resolve();
});
}
var s = new SiteParams();
s.load.done(function() {
$("<div/>", {id:"title", text: s.NomeSito}).appendTo("#main");
});
You have the wrong this inside the callback to $.each (and the callback to getJSON). Try that:
function SiteParams(){
var that = this;
$.getJSON("parse/parametri.php",function(data){
$.each(data,function(index,value){
that.NomeSito = value.nomesito;
that.URLSito = value.urlsito;
that.EmailAutore = value.email;
that.NomeAutore = value.nomeautore;
});
});
}
Note that it doesn't make much sense to loop with each if your response only contains a single object. And if it contained multiple objects, every object would overwrite the previous. So, if your response is really an array with a single item inside, you can simple use this:
function SiteParams(){
var that = this;
$.getJSON("parse/parametri.php",function(data){
that.NomeSito = data[0].nomesito;
that.URLSito = data[0].urlsito;
that.EmailAutore = data[0].email;
that.NomeAutore = data[0].nomeautore;
});
}
getJSON is asynchronous, so you need to pass a callback function. Try this:
function SiteParams(cb){
$.getJSON("parse/parametri.php",function(data){
$.each(data,function(index,value){
this.NomeSito = value.nomesito;
this.URLSito = value.urlsito;
this.EmailAutore = value.email;
this.NomeAutore = value.nomeautore;
cb(this);
});
});
}
new SiteParams(ModuleBase);
function ModuleBase(website){
$("<div/>",{id:"title", text:website.NomeSito}).appendTo("#main");
}

foreach object looping adding on top of the stack

I have an js, object which is something like this:
function test{
this.variable = {};
this.populate = function(){
// do some crap....
// and i populate the object like this
this.variable{xyz..} = new object();
}
this.outputThecrap(){
for (var key in data) {
if (data.hasOwnProperty(key)) {
if(data[key].idParent != '0'){
//do some stuff
}
}
}
}
this.addSomeOnBeginigQQ(){
// how do i do that!!!!Q_Q
this.variable{blabla...} = new blabla();
}
}
now after I populate the object like
var t = new test();
t.populate();
t.addSomeOnBegining();
t.outputThecrap();
I get the problem that the added properties wind up on the end of the loop ... and I need them to be on the top
Anyone has some idea how to solve this?
UPDATE:
The structure of the object is not open to change. i cant use the array as a container either, that s out of question.
If you want a stack, you will need to use an Array - a list with a defined order. Object properties have none in JavaScript, there is nothing like "associative arrays". Also, you should the prototype.
You can set properties of array just as you do with objects, but the property names need to be numerically (i.e. integers). You then loop over them with a for-loop. Array objects also have some extra methods, for example to add items in the beginning or the end (which I have used below):
function Test() {
this.data = []; // an array
}
Test.prototype.populate = function(){
// populate the array like this
this.data.push({…});
};
Test.prototype.outputThecrap = function(){
for (var i=0; i<this.data.length; i++) {
var item = this.data[i];
if (item /* has the right properties*/)
//do some stuff
}
};
Test.prototype.addSomeOnBeginning(){
this.data.unshift({…});
};
Then use it like this:
var t = new Test();
t.populate();
t.addSomeOnBeginning();
t.outputThecrap();
The "ordered key array" looks like this:
function Test() {
this.data = {}; // the object
this.order = []; // an array
}
Test.prototype.populate = function(){
this.data["something"] = {…}
this.order.push("something");
};
Test.prototype.addSomeOnBeginning(){
this.data["other"] = {…};
this.order.unshift("other");
};
Test.prototype.outputThecrap = function(){
for (var i=0; i<this.order.length; i++) {
var key = this.order[i],
item = this.data[key];
if (item && key /* fulfill your requirements */)
// do some stuff
}
};

Categories