Looping json object key => array - javascript

I'm pulling in a json object, this is the result of a $.parseJSON output. I understand it needs a handler to help it but not to sure what belongs in the helper. Reading the other users questions, they seem to be able to jump through the next hoop due to having a constant key, unfortunately in my case it's always different.
Json output
[
{
"High blood pressure?": [
"no",
"string"
]
},
{
"Cancer?": [
"no",
"string"
]
},
{
"Asthma or a breathing disorder?": [
"no",
"string"
]
}
]
Loop
{{#each screen_data}}
<tr>
<td class="bold">{{this}}</td>
</tr>
{{/each}}
Results in
[Object object][Object object][Object object]......

It's because you've got an array of objects, and that's what you're telling your template to write out.. the object. It seems like you want to write out the only property on the root of the object, which is a question.
try this:
{{#each screen_data}}
<tr>
<td class="bold">{{this[0]}}</td>
</tr>
{{/each}}
That's a strange JSON structure you have there, I must say. Generally it's considered poor form to use the object property name as a carrier of data like that.
EDIT: I'd recommend changing that structure to something that better represents your data... like so:
[{
question: "High blood pressure?",
answers: [
"no",
"string"
]
},
{
questions: "Cancer?",
answers: [
"no",
"string"
]
},
{
question: "Asthma or a breathing disorder?",
answers: [
"no",
"string"
]
}]
Which would then mean your template would look like so:
{{#each screen_data}}
<tr>
<td class="bold">{{this.question}}</td>
</tr>
{{/each}}

You can try this fiddle below. It will give you all the keys from the JSON data
http://jsfiddle.net/tariqulazam/SjugS/
var data= [
{
"High blood pressure?": [
"no",
"string"
]
},
{
"Cancer?": [
"no",
"string"
]
},
{
"Asthma or a breathing disorder?": [
"no",
"string"
]
}
];
for (var key in data) {
for (var item in data[key]) {
alert(item);
}
}

Related

How to get a specific or multiple values (or keys) from nested JSON

I have a (nested) data structure containing objects and arrays. How can I extract the information, i.e. access a specific or multiple values (or keys)?
{
"data": [{
"name": "name1",
"value": "value1",
"list": [{
"sname": "sname1",
"svalue": "svalue1"
}, {
"sname": "sname2",
"svalue": "svalue2"
}]
}]
}
jQuery
var pk = $("#pk").val();
console.log(pk);
url = "/register/search?id=" + pk;
console.log(url);
$('#largeTable').DataTable({
"ajax": url,
"bDestroy": true,
"columns": [{
"data": "name"
},
{
"data": "value"
},
{
"data": "list.1.sname"
},
{
"data": "list.1.svalue"
},
{
"data": null,
"defaultContent": editview
}
]
});
Here it is possible to display either first or second list values by using list.1 or list.0
But I want two values at a time.
Also, how could I access the svalue of the second item in list?
I tried with data.list[1] but:
TypeError: data.list is undefined
Since data is an array, you should first get the item - and since you only have one item - you'd use data[0], and then get access to the list property like data[0].list[1] - this will give you the second item in the list - but since you are interested in a specific property (svalue) of this item, you will then access it like this: data[0].list[1].svalue.
A better approach would be to loop through the items in the data array - and then for each item, loop through the items in the list array. See #Rajesh's comment.
I hope that helps;
Specifically you can access it like this object.data[0].list[1].svalue. The reason data.list is undefined is because data corresponds to an array data: [{ }] this is why we use data[0], but data itself is a key in an object so before you can get to data you need to access it. If the objects name where data resides were object (like I did below) then it'd be accessed like this object.data[0]
const object = {
"data": [{
"name": "name1",
"value": "value1",
"list": [{
"sname": "sname1",
"svalue": "svalue1"
}, {
"sname": "sname2",
"svalue": "svalue2"
}]
}]
}
console.log(object.data[0].list[1].svalue)

Intersecting two objects in angular 2

What I want to do is intersect two objects.
I want to compare the objects, and if they have same values on same keys, just add them to another object.
obj1 = { "Projects": [ "test" ], "Companies": [ "facebook", "google", "yahoo" ], "Locations": [ "LA", "NY" ], "Interests": [] }
obj2 = { "Projects": [ "test" ], "Companies": [ "netflix", "skype", "facebook" ], "Locations": [ "sttugart", "torino", "LA" ], "Interests": [] }
The result will be:
obj3 = { "Projects": [ "test" ], "Companies": [ "facebook" ], "Locations": [ "LA" ], "Interests": [] }
What i tried is something like this:
intersect(obj1, obj2)
for(let key of obj1)
if(obj2[key] == obj1[key]) obj3[key] = obj2[key];
And yes, i did checked SO for other solutions, i had no result.
EDIT
My attempt dind't probably work because my object is not an array type or a string type
This isnt really a problem just for angular 2 but more javascript in itself. No angular functions will probably help you here
Using lodash or underscore.js might prove to be more productive and useful
However if you insist that you need to do this in your own way. there are two cases
One is that you already know how many objects you would be comparing
Two is that you don't know how many objects you would be comparing
For case one it would a simple for loop with && cases for logical comparisons
For case two i would suggest you first push all your objects that need to be compared into an array and iterate through there.
Use lodash
Here you will find a good documentation:
https://lodash.com/docs/4.16.2#intersection
We often use it with good experience

Functional Javascript algorithm not returning the expected result from a filter

I am practicing using map(), filter(), and concatAll()in Javascript. I am expecting the code below to return the following:
[{
"id": 70111470,
"title": "Die Hard",
"boxart":"http://cdn-0.nflximg.com/images/2891/DieHard150.jpg"
}]
It is not pulling in the URL from the boxart and I am not sure why. I get the following output when I run my code:
[{"id": 70111470,"title": "Die Hard"}]
function() {
var movieLists = [
{
name: "Instant Queue",
videos : [
{
"id": 70111470,
"title": "Die Hard",
"boxarts": [
{ width: 150, height:200, url:"http://cdn-0.nflximg.com/images/2891/DieHard150.jpg" },
{ width: 200, height:200, url:"http://cdn-0.nflximg.com/images/2891/DieHard200.jpg" }
],
"url": "http://api.netflix.com/catalog/titles/movies/70111470",
"rating": 4.0,
"bookmark": []
}
]
}
];
getBoxart = function(boxart){
return boxart.width==150;
};
getVideoData = function(video){return {id: video.id,
title: video.title,
boxart: video.boxarts.filter(getBoxart).url}
};
getVideos = function(movie){return movie.videos.map(getVideoData)}
return movieLists.map(getVideos).concatAll();
}
the issue is this line: video.boxarts.filter(getBoxart).url
filter is returning an array of boxarts (which does not have a url property)
you either need to map after filter to return an array of urls, or just grab the first one
That's because
video.boxarts.filter(getBoxart)
returns an array (if that's the native implementation of filter, but probably for any other implementation as well), and then doing
video.boxarts.filter(getBoxart).url
returns undefined since arrays don't have a url property...
You probably need to do:
video.boxarts.filter(getBoxart)[0].url

How do I create a subset of a JSON file using key values that exist in both using getJSON?

I have a large JSON file that I want to use to create a subset using vars that I'll be storing in localStorage. I prefer jQuery but other approaches are welcomed.
The id (which will exist in both places) will be used to match and determine that the keys/values should be part of the new subset.
The "master" JSON file is structured similar to this:
{
"myStuff": [
{
"id": "53b0c01de4b0deedb5c9015f",
"brief": "Joe's Stuff",
"author": "Joe"
},
{
"id": "545fb8c4e4b03cfb303de9f2",
"brief": "Jim's Stuff",
"author": "Jim"
},
{
"id": "54676ae4e4b09ffed41ffc7c",
"brief": "Mary's Stuff",
"author": "Mary"
}
]
}
I have flexibility in how the items that will determine the subset are presented.It will always contain multiple values. Those are "id" value to match an existing "id" value in the master JSON file.
For example, I can get a string out of localStorage that would look like this:
{"id1":"545fb8c4e4b03cfb303de9f2","id2":"54676ae4e4b09ffed41ffc7c"}
or as simple as this:
545fb8c4e4b03cfb303de9f2, 54676ae4e4b09ffed41ffc7c
Suggestions to which approach may be better are welcomed.
So, in this case, The subset should return just the stuff from Jim and Mary and ignore Joe.
{
"myStuffSubset": [
{
"id": "545fb8c4e4b03cfb303de9f2",
"brief": "Jim's Stuff",
"author": "Jim"
},
{
"id": "54676ae4e4b09ffed41ffc7c",
"brief": "Mary's Stuff",
"author": "Mary"
}
]
}
Please let me know if I've missed something in the explanation. And, I find fiddles help me learn the best. Thanks!
I've created a plnkr for you.
Basically, the filter function will get the string separated by commas and search inside your JSON:
function search(str, obj) {
var arr = str.split(',');
return obj.myStuff.filter(function(o) {
return arr.indexOf(o.id) > -1;
});
}

Keep order of objects inside a JSON String after they are parsed

I receive the following JSON string from an API function.
"Inbound": {
"callRelatedFields": ["ANI",
"DNIS"],
"objects": {
"Contact": [{
"displayName": "Name",
"apiName": "Name"
},
{
"displayName": "Email",
"apiName": "Email"
}],
"Account": [{
"displayName": "Account Name",
"apiName": "Name"
},
{
"displayName": "Phone",
"apiName": "Phone"
},
{
"displayName": "Fax",
"apiName": "Fax"
}],
"cnx__Phone__c": [{
"displayName": "Phone Name",
"apiName": "Name"
},
{
"displayName": "Phone Number Line 1",
"apiName": "cnx__Phone_Number_Line_1__c"
},
{
"displayName": "Phone Number Line 2",
"apiName": "cnx__Phone_Number_Line_2__c"
},
{
"displayName": "Type",
"apiName": "cnx__Type__c"
},
{
"displayName": "Location",
"apiName": "cnx__Location__c"
},
{
"displayName": "Call Manager",
"apiName": "cnx__Call_Manager__c"
},
{
"displayName": "Mac Address",
"apiName": "cnx__Mac_Address__c"
}]
},
"screenPopSettings": {
"screenPopsOpenWithin": "ExistingWindow",
"SingleMatch": {
"screenPopType": "PopToEntity"
},
"NoMatch": {
"screenPopType": "DoNotPop"
},
"MultipleMatches": {
"screenPopType": "DoNotPop"
}
}
}
The order of the objects inside "objects" is important!
But when i parse this JSON string with JSON.parse, the order of those objects is lost.
Is there any good way to keep the order of those objects after they are parsed.
I tried to manipulate the string and convert the whole "objects" into an array, but this turned out to become way too complicated and hacky.
I have a suspicion that the thing that makes you think the keys have changed order is that Chrome devtools show objects with their keys sorted in alphabetical order. Whereas if you use Object.keys() or the equivalent JS to manually iterate through the keys, you will find they come out in the order they were defined in the JSON string.
Here is the equivalent JS for Object.keys():
function objectKeys(obj) {
var keys = [];
if (!obj) return keys;
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
keys.push(key);
}
}
}
When I call this with the objects part of the parsed object I get the following array:
["Contact", "Account", "cnx__Phone__c"]
Unfortunately object properties are unordered in JavaScript so you shouldn't rely on being able to iterate over them in a particular sequence.
I would suggest accessing the properties by name in the order you need them, rather than just iterating over the list.
As per the JSON standard, an object is unordered. So if you care about the order "Contact", "Account", "cnx__Phone__c", put them in an array ([]).
Maybe it's enough to put the property names themselves in an array next to the .objects themselves, so that you still can access them by their names. Many structures are valid solutions.
This solution works only if the properties and the data does not contain one of these characters: {, } and :.
Maybe you replace the curly brackets to square brackets and ": to #",. After that, you can the JSON string parse and get all objects replaced by arrays. The reading is: first value is the property (marked with # at the end) and the second value is the value.
The replacement machanism shuld be improved, in particular the replacement of ":, which can sometimes be wrong, and the search of the curly brackets.
var json = '{"Inbound":{"callRelatedFields":["ANI","DNIS"],"objects":{"Contact":[{"displayName":"Name","apiName":"Name"},{"displayName":"Email","apiName":"Email"}],"Account":[{"displayName":"Account Name","apiName":"Name"},{"displayName":"Phone","apiName":"Phone"},{"displayName":"Fax","apiName":"Fax"}],"cnx__Phone__c":[{"displayName":"Phone Name","apiName":"Name"},{"displayName":"Phone Number Line 1","apiName":"cnx__Phone_Number_Line_1__c"},{"displayName":"Phone Number Line 2","apiName":"cnx__Phone_Number_Line_2__c"},{"displayName":"Type","apiName":"cnx__Type__c"},{"displayName":"Location","apiName":"cnx__Location__c"},{"displayName":"Call Manager","apiName":"cnx__Call_Manager__c"},{"displayName":"Mac Address","apiName":"cnx__Mac_Address__c"}]},"screenPopSettings":{"screenPopsOpenWithin":"ExistingWindow","SingleMatch":{"screenPopType":"PopToEntity"},"NoMatch":{"screenPopType":"DoNotPop"},"MultipleMatches":{"screenPopType":"DoNotPop"}}}}';
json = json.replace(/{/g, '[').replace(/}/g, ']').replace(/"\:/g, '#",');
json = JSON.parse(json);
document.write('<pre>' + JSON.stringify(json, 0, 4) + '</pre>');
#GregL is right the JSON parsed came in alphabetic or in case of a number in ascending order and to keep the order you'll need an incremented number logic like:
var position_in_array = 0
var name = 'screenPopSettings'
object[`${position_in_array}${name}`] = value
position_in_array += 1
The parseJson returns data in object form and object doesn't has index. So we should define custom index of data array, if we want to keep the array index.
Example:
$arr[0] = array(
'Contact'=>array(
'key1'=>'val',
)
);
$arr[1] = array(
'Account'=>array(
'key1'=>'val',
)
);
It will produce the output as per the array index originally defined before parseJson function call.

Categories

Resources