JavaScript: How to properly loop through array and use values as keys? - javascript

I am getting a JSON-string from a remote endpoint and want to use values as keys. So I am looping through the result like that:
(function() {
// Create the connector object
var myConnector = tableau.makeConnector();
var definitions = [];
// Define the schema
myConnector.getSchema = function(schemaCallback) {
$.ajax({
url: apiUrl,
type: 'GET',
crossDomain: true,
cache: false,
headers: {
'X-Auth-Token':'123',
'X-Auth-User':'user1'
},
dataType: "json",
success: function(response){
$.each(response,function(key,value){
console.log("inside loop");
console.log(value);
definitions[value.id]
= value.name;
});
console.log("inside ajax");
console.log(definitions);
}
});
console.log("done");
console.log(definitions);
// this is where I want to loop through my result
// whithout success (no console output
for (var key in definitions) {
console.log(key);
}
}; // myConnector.getSchema = function(schemaCallback) {
})(); //function() {
This is the response from the API:
[
{
"id": 123,
"name": "Name1"
},
{
"id": 456,
"name": "Name2"
},
{
"id": 789,
"name": "Name3"
}]
This is the output of the first log command, inside the loop:
{id: 123, name: "Name1"}
id: 123
name: "Name1"
__proto__: Object
The problem is, the last log looks like this:
[123: "Name1", 456: "Name3", 789: "Name4"]
123: "Name1"
456: "Name2"
789: "Name3"
length: 0
__proto__: Array(0)
The problem is clearly: The array length is shown as zero. And this I do not understand.
Later in this script I want to loop through this array again, but because of this strange result, I am not able to address the index keys.
What is it, that I am doing wrong?
Additional information
I am working on a web connector for Tableau that will connect to an RESTful service's endpoint. Unfortunately I cannot publish the actual RESTful URL, because it provides private data.
I am using this simulator: http://tableau.github.io/webdataconnector/Simulator/
I added all the surroundings to the upper source code. There are few more lines of source code, but it's absolutely not related to my work (one more different loop and variable definitions).
I now tried the script in Firefox (Chrome before). The only result I get here is
done myConnector.js:97:5
[]
​
length: 0
​
<prototype>: Array []
All the other console.log's are not triggered.
Also Firefox complains about CORS, this is known because I already fixed the CORS-header server-side. But nevertheless at the end data is being received and populated to the simulator I am using (see URL above)!
Clearly I am misunderstanding something here...

Try this. Not work in IE. For crossbrowsers support use regular for loop.
for (var object of response) {
console.log(object.id);
console.log(object.name);
}
Regular for
var len = response.length;
for ( var i = 0; i < len; i++ ) {
var currentObject = response[i];
console.log(currentObject.id);
console.log(currentObject.name);
}
In this way you get properties and then can use they as key for looping over another array/object.

You can try initializing definitions as an object instead of array ie. var definitions = {} and the ids its properties. So that you can easily loop through it with a for..in loop.
As the AJAX call is async the log might run on the empty array definitions.
for (id in definitions) {
// Logic
}
var len = Object.keys(definitions).length

OK, this is on me and a misunderstanding of Ajax and asynchronious request. The comments on my question helped to see the problem.
As stated above, I am calling this script from another server (http://tableau.github.io/webdataconnector/Simulator/). The script itself sends a request to a third server.
Forcing the ajax-function to work synchroniously works:
$.ajax({
url: apiUrl,
type: 'GET',
crossDomain: true,
cache: false,
async: false,
...})
Now the console show the array as actually filled:
(790) [empty × 123, "Name1", empty × 123, "Name2", empty × 333, "Name3"]
123: "Name1"
456: "Name2"
789: "Name3"
length: 929
__proto__: Array(0)
So finally, it's not about referencing the array / object the wrong way, it's about the asynchronious call.

Related

Bootstrap-3-Typeahead getting right json key

I am useing this plugin for an ajax auto complete feature
https://github.com/bassjobsen/Bootstrap-3-Typeahead
the bootstrap-3 type. The code below is working but I do not know why it works. Specifically how the the process and response parameter work.
$(document).ready(function() {
$('#typeahead-input').typeahead({
autoSelect: true,
minLength: 1,
delay: 400,
source: function (query, process) {
$.ajax({
url: '/api/location',
data: {sstr: query},
dataType: 'json'
})
.done(function(response) {
// console.log(response)
return process(response);
});
}
});
});
my json looks like this
[
{
"id": "123",
"name": "Frederiksted",
"state": "VI",
"zip_code": "840"
}
]
What if i wanted to autocomplete to populated based on on the zip_code field how would i do it?
I have tried doing "response.zipcode" but it comes out as undefined
First, response.zipcode will be undefined because response is a Array not a Object. You access zipcode by response[0].zip_code ( And also note that your property name is not 'zipcode' it is 'zip_code' ).
Second, documentation of the "source" property says: The data source to query against. May be an array of strings, an array of JSON object with a name property or a function.
So, what you give to the "process" method most probably should be a array of strings or array of JSON objects where each JSON object has a "name" property.
If your response is correct and returns an array of objects like you say,
then it means your objects each have a 'name' property,so that property is displayed. If you want to display something else, you need to create a new String array from the response:
So I would try this:
.done(function(response) {
// get the response and create a new array of Strings
var names = $.map (response, function(item) {
return item.name + '-' + item.zip_code;
});
// console.log(response)
return process(names);
});
or another way:
.done(function(response) {
// get the response and change the 'name' of each object
$.each (response, function() {
this.name = this.name + '-' + this.zip_code;
});
// console.log(response)
return process(response);
});
I think you have issue with json format:
[
"id": "123",
"name": "Frederiksted",
"state": "VI",
"zip_code": "840"
]

Manipulate ajax response

I have a ajax post method. I get an object from the backend
$.ajax({
type: "POST",
url: URL_one,
data: submitData
}).then(function (response) {
console.log("Ajax response", response);
});
and when i do a console.log(response); inside the post method, i see the following data.
>Object{Info:Array[200]}
>Info:Array[200]
>[0-99]
>0:Object
name:'Ashley'
on_pay: true
valid:"0"
>[100-199]
So each array has objects like one mentioned above with name, on_pay and valid. I want to do the following
Since all on_pay values are true in my case, i need to convert it to false. Also valid has string of 0. I need to put all values as blank instead of 0.
Is it possible to do ?? Can someone please shed some light on these.
Considering the JSON structure that you show, following should work to change the on_pay value:
response.Info.forEach(function(item){
item.on_pay = false;
});
If I'm understanding your question correctly, response is an array of items. You want to keep those items intact, but turn the on_pay property false and valid to an empty string.
You can use Array::map() to transform each item.
/*jslint node:true*/
"use strict";
// I am assuming your response looks something like this
var response = {
Info: [
{
name: "Ashley",
on_pay: true,
valid: "0"
},
{
name: "Jim",
on_pay: true,
valid: "0"
},
{
name: "John",
on_pay: true,
valid: "0"
}
]
};
// This will produce a new variable that will hold the transformed Info array
var fixedResponseInfo = response.Info.map(function (item) {
item.on_pay = false;
item.valid = "";
return item;
});
// This will edit the response.Info array in place
response.Info.forEach(function (item) {
item.on_pay = false;
item.valid = "";
});
console.log(fixedResponseInfo);
console.log(response);
This will keep your original response variable and produce a new variable fixedResponseInfo that contains the transformed array. If you don't care whether data in response is changed, you can use Array::forEach() to iterate instead.

Accessing JSON objects from objects without titles in JQuery

I am receiving this JSON file back from an AJAX call:
[
{
"LINKNAME": "Annual Training",
"HITS": 1
},
{
"LINKNAME": "In Focus Newsletter",
"HITS": 1
},
{
"LINKNAME": "NITA (secured)",
"HITS": 1
},
{
"LINKNAME": "Your Current Events",
"HITS": 1
},
]
Here is my AJAX call:
$(document).ready(function(e) {
$.ajax({
method: "GET",
url: url,
}).done(function(api) {
console.log(api);
var obj = JSON.parse(api),
totRes = Object.keys(obj).length;
$.each(obj.children, function (index, value) {
alert(value);
});
}).fail(function( jqXHR, textStatus ) {
alert('Service Catalog: Error loading '+jqXHR+' data. Request fail caused by: '+textStatus);
});
});
I need to be able to extract the data from the JSON and use it but since the JSON objects aren't gioven a title then I am unsure how to extarpolate the data inside the inner object. Thanks in advance. Please ask if you do not understand my question.
Your JSON is just an array of plain objects.
To iterate over an array, you can use various methods. Since you're using jQuery, I'll just suggest $.each:
var arr = JSON.parse(api);
$.each(arr, function(i, obj) {
// access whatever property you want... obj[LINKNAME] or whatever
});
You can also use Array.prototype.forEach, or even just your basic for loop:
arr.forEach(function(obj) {
// obj is the current plain object... e.g. { LINKNAME: 'whatever', HITS: 0 }
});
I would also consider paying attention to how you are referring to the objects that you are receiving. While it is true that arrays are objects, and plain objects are objects, I would probably stick to referring to an array as an array, and a plain object as an object. This is because what you are receiving, in the form of JSON, is an array object of plain objects (or more simply, an array of objects).
Calling the array an "object" and referring to it as obj may confuse you when reading through the code quickly (yes, it is a good abstraction for potential extensibility if you end up not always receiving an array, but that's not the case here.)
Also, to once you have access the object in the each loop, you can iterate over the properties of the object if you need to (taken from this answer):
var obj = {
"a": 1,
"b": 2,
"c": 3
};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
// or if (Object.prototype.hasOwnProperty.call(obj,prop)) for safety...
alert("prop: " + prop + " value: " + obj[prop])
}
}
First, you can add the setting dataType: 'json' when you send a request. This way you'll have api as javascript array.
Then you'll be able to iterate it via javascript for.
$.ajax({
method: "GET",
url: url,
dataType: "json"
}).done(function(api) {
for (var i = 0; i < api.length; i++) {
var name = api[i]["LINKNAME"],
hits = api[i]["HITS"];
// ...
}
// ...
$(document).ready(function(e) {
$.ajax({
method: "GET",
url: url,
}).done(function(api) {
if (api && api.length > 0) {
api.forEach(function (item) {
console.log(item); // logs whole object
console.log('item name %s', item.LINKNAME);
console.log('item hits %s', item.HITS);
});
}
}).fail(function( jqXHR, textStatus ) {
alert('Service Catalog: Error loading '+jqXHR+' data. Request fail caused by: '+textStatus);
});
});
You can filter the results to make sure you're only using objects that contain both 'LINKNAME' and 'HITS' pretty easily:
.done(function(api) {
if (api && api.length > 0) {
var objs = api.filter(function (item) {
return item.hasOwnProperty('LINKNAME') && item.hasOwnProperty('HITS');
});
objs.forEach(function (item) {
console.log(item); // logs whole object
console.log('item name %s', item.LINKNAME);
console.log('item hits %s', item.HITS);
});
}
});

Angular Ajax request sending object

i am editing content in an object saved in my AngularJs scope. Once submited i execute the following function:
$scope.saveQuestion = function(){
var request = $http({
method: "post",
url: "/manager/evaluations/evaluations/manage_questions/537c6179-8ed8-49b4-ac6b-25715f550349",
data: {EvaluationQuestion: $scope.newquestion}
});
}
$scope.newquestion has the following object:
[relevance: 3, evaluation_topic_id: 1, type: "text", action: "add", name: "asdfasdfsadfas"]
But the ajax request on the is just showing a Request Payload with:
Request Payloadview source
{EvaluationQuestion:[]}
EvaluationQuestion: []
Can any one guess why the sent data is empty?
It seems your $scope.newquestion is an Array, not an Object.
JSON doesn't support an Array data type with named keys in it. For example:
var foo = [];
foo['bar'] = 'One';
foo.baz = 'Two';
JSON.stringify(foo); // return "[]"
If the $scope.newquestion isn't required to be an Array, just use an Object.
Instead of
$scope.newquestion = [];
change it to:
$scope.newquestion = {};
I think you are using a wrong JSON syntax in $scope.newquestion.
Here you are defining an object which is supposed to be enclosed in {} but you are enclosing it in [] which stands for an array. I js arrays you cannot have [name1: value1, name2: value2].
Try replacing the square brackets with curely brackets, something like this:
{relevance: 3, evaluation_topic_id: 1, type: "text", action: "add", name: "asdfasdfsadfas"}
Hope that helps.
Try this:
data: {EvaluationQuestion: angular.toJson($scope.newquestion)}

Javascript loop + Object Issue: How to get required item in object with loop

I am facing some trouble with loops, objects
I have json like this;
var jsonPermission = {"permissions": [
{"permissionId": 1, "permissionName": "Admin Permission", "roleDesc": "This is an Admin Permission"},
{"permissionId": 2, "permissionName": "Manager Permission", "roleDesc": "This is a Manager Permission"},
{"permissionId": 3, "permissionName": "User Permission", "roleDesc": "This is a user Permission"}
]
};
And I have to make object like this;
[
{ data: "Admin Permission", type: ["permission"] },
{ data: "Manager Permission", type: ["permission"] },
{ data: "User Permission", type: ["permission"] }
]
So I used following code;
//For Permissions
var permissions_len = jsonPermission.permissions.length;
var arr_permissions = [];
var permission_type = ["permission"];
for(var i=0;i<permissions_len;i++){
var obj_permissions = {};
obj_permissions["data"] = jsonPermission.permissions[i].permissionName;
obj_permissions["type"] = permission_type;
arr_permissions.push(obj_permissions);
}
But instead I am getting like this:
[
{ data: "Admin Permission", type: [1] },
{ data: "Manager Permission", type: [1] },
{ data: "User Permission", type: [1] }
]
How to perform?
I think it is a problem of the tool you are using to evaluate the result, if you log the result to console using firefox console.log() it will give you the result as you have shown. But if you properly inspect the value using for loop in your code you can find that the values are correct.
Inspect the values as shown below
var permissions_len = jsonPermission.permissions.length;
var arr_permissions = [];
var permission_type = ["permission"];
for(var i=0;i<permissions_len;i++){
var obj_permissions = {};
obj_permissions["data"] = jsonPermission.permissions[i].permissionName;
obj_permissions["type"] = permission_type;
arr_permissions.push(obj_permissions);
}
for(var i=0;i<permissions_len;i++){
var a = arr_permissions[i];
console.log(a.data, a.type)
}
You can test it here.
How about:
obj_permissions["type"] = [ permission_type[0] ];
instead of:
obj_permissions["type"] = permission_type;
See the difference? You're working with arrays.
[EDIT: actually there isn't much difference, but this still clarifies. See comments.]
Since permission_type is an array literal, the type properties of the final array items end up being arrays of one element. If you did not intend that, remove the array notation.
For example:
var source = jsonPermission.permissions;
var arr_permissions = [];
for(var i=0;i<source.length;i++){
arr_permissions.push({
data: source[i].permissionName,
type: ["permission"] // or type: "permission" if you didn't want an array
});
}
This version of the code has been simplified a bit, but also has a very important difference: each item's type is not the same object anymore, so you cannot change all of them at once (either intentionally or accidentally, which has the bad habit of occurring when you don't expect it).

Categories

Resources