Extracting data from a JSON object - javascript

I'm trying to extract the text from this JSON return:
{
"threaded_extended": {},
"messages": [
{
"body": {
"parsed": "the network. Take a moment to welcome Jason.",
"plain": " network. Take a moment to welcome Jason.",
"rich": "Jason."
},
"thread_id": 56,
"client_type": "Wb",
"client_url": "https://www.yammer.com/",
"system_message": true,
"direct_message": false,
"chat_client_sequence": null,
"language": "en",
"notified_user_ids": [],
"system_message_properties": {
"subtype": "created_membership"
},
"privacy": "public",
"attachments": [],
"liked_by": {
"count": 0,
"names": []
},
"content_excerpt": " Jason.",
"group_created_id": null
}
]
}
my function looks like this, but it keeps saying undefined - sorry if this is a dumb question, my logic is that the object is value, then messages is an attribute, and then plain should be an attribute of that. Am I doing something stupid? Appreciate any help
function getData(returnData){
$.each(returnData, function(key, value){
if(value != undefined){
$('#test').append(value.messages.plain);
}
});
}

$('#test').append(value.messages[0].plain);
messages is an array so you need to provide an index.
Edit : I thought returnData was an array, if it's not the case you're looping on the wrong object. Loop through returnData.messages. and get value.body.plain

Iterate through returnData.messages the array in your object. Then you can access each message item in the array, whereas the plain value is on body.plain for each value
function getData(returnData){
$.each(returnData.messages, function(key, value){
if(value != undefined){
$('#test').append(value.body.plain);
}
});
}

Related

Stringify and parse complex object with nested arrays from localStorage

I have a very complex dictionary object consisting of very deeply nested combinations of objects and arrays.
I use a custom deepCopyObject function to make a deep copy of my object throughout my code. That works fine, I'm only including it because it's the only way I'm able to copy the object without a shallow reference.
The issue comes when I try to store and retrieve it from localStorage with parse and stringify. The below code returns:
nextQuestion local_user_dict is [object Object]
test.html:1 Uncaught SyntaxError: Unexpected token o in JSON at position 1
The code below was structured by copying the object from the console in the browser and editing the keys/values. I left all of the structure intact including the "null" values which I didn't include but I assume is due to it being an array nested within the object.
I'm told that stringify and parse should work with deeply nested and complex objects including with arrays (Though I've read elsewhere online that's not true). How can I correctly pass this object and retrieve it from localStorage?
If I use my deep copy function on the object it works fine and displays as it should, the problem only occurs when stringifying and parsing from localStorage.
var test_dict = {
"questions": {
"obj1": {
"words": [
null,
{
"test1": {
"test2": "test7",
"test3": "test6"
},
"test4": "test5"
},
{
"test8": {
"test9": 0,
"test10": "2",
},
"test11": [
null,
{
"test12": {
"no": 0,
"yes": 1
},
"test13": "test14"
},
{
"test15": {
"no": 0,
"yes": 1
},
"test16": "test17"
},
{
"test18": {
"no": 0,
"yes": 1
},
"test19": "test20"
}
]
}
]
}
}
}
localStorage.setItem('user_dict', deepCopyObject(test_dict))
let local_user_dict = localStorage.getItem('user_dict')
console.log('nextQuestion local_user_dict is ', local_user_dict)
let parsed_local_user_dict = JSON.parse(local_user_dict)
console.log('nextQuestion parsed_local_user_dict is ', parsed_local_user_dict)
user_dict = deepCopyObject(parsed_local_user_dict)
console.log('nextQuestion user_dict is ', user_dict)
function deepCopyObject(inObject) {
let outObject, value, key
if (typeof inObject !== "object" || inObject === null) {
return inObject
}
outObject = Array.isArray(inObject) ? [] : {}
for (key in inObject) {
value = inObject[key]
outObject[key] = deepCopyObject(value)
}
return outObject
}
localstorage stores strings. not objects.
change
localStorage.setItem('user_dict', deepCopyObject(test_dict))
to
localStorage.setItem('user_dict', JSON.stringify(test_dict))
and ditch the copy. you can actually use JSON parse and stringify to copy objects.

Merge and array from within an object to every key form object

So, I have an object as follows:
custom_fields:{
21:{
edit:true
required:true
show:true
}
}
Which in my angular controller is stored here: $scope.page.custom_fields
Within this object I have another one, like this:
custom_fields:{
21:{
edit:true
required:true
show:true
}
22:{
edit:true
required:true
show:true
}
data:[
0:{
display_name:"Text"
id:21
name:"Text"
value:[
0:{"TextHere"}
]
}
1:{
display_name:"Text"
id:22
name:"Text"
value:[
0:{"TextHere"}
]
}
]
}
This one is stored like this: $scope.page.custom_fields.data = response.data.custom_fields;
As you can see the first one is an object of objects while the second one is an array of objects. I don't know why they ended up like this, but I would need to assign the first key in data to the first key in custom fields, so they would look like this in the end:
custom_fields:{
21:{
edit:true
required:true
show:true
display_name:"Text2"
id:21
name:"Text"
value:[
0:{"TextHere"}
]
}
}
I should do this in the angular controller. As you can see every id from data corresponds to the key in custom_fields (in this case 21:{} and data[0:{id:21}])
But they are being put in order by a foreach in php so there is no need to make a foreach in js too, I only have to assign in order every key from custom_fields.data to every key from custom_fields
But how can I do this?
data[0:{id:21}]
No, this is not possible.
Please refer link
numeric-type-as-an-object-key
It will be very difficult to use the $scope.page.custom_fields.21 later in your code. So better use it as array format instead of object. Following code will help you parse it in array of objects of custom fields.
angular.forEach($scope.custom_fields.data, function(value, idx){ // may be $scope.custom_fields.custom_fields.data as per your code. Please correct accordingly.
if($scope.custom_fields[value.id]){
angular.merge($scope.custom_fields.data[idx], $scope.custom_fields[value.id]);
delete($scope.custom_fields[value.id]);
}
});
$scope.custom_fields = $scope.custom_fields.data;
console.log($scope.custom_fields);
let custom_fields = {
"21": {
"edit": true,
"required": true,
"show": true
},
"22": {
"edit": true,
"required": true,
"show": true
},
"data": [{
"display_name": "Text",
"id": 21,
"name": "Text",
"value": ["TextHere"]
}, {
"display_name": "Text",
"id": 22,
"name": "Text",
"value": ["TextHere"]
}]
};
custom_fields.data.forEach(function(item) {
let obj = custom_fields[item.id];
for (let attr in item)
obj[attr] = item[attr];
});
//Remove the data property
delete custom_fields.data;
console.log(custom_fields);
As I said in comment, I think you need a loop to asign each custom fields
var i = 0;
for (var key in custom_fields) {
if (custom_fields.hasOwnProperty(key)) {
// only if you are sure that data is ordered, else must be filter data by custom_fields[key].id
custom_fields[key].display_name = data[i].display_name;
custom_fields[key].name = data[i].name;
custom_fields[key].value = data[i].value;
i++;
}
}
I hope this will help you

Push Json filtered key values to nested ul with Javascript

I need help pushing the values from a filtered json, I need this generate a nested ul list, I can not modify the json format at this point, I you check the console.log you will see the values to create the list, at this point I can't figure how to complete the 'for loop' to render the html markup needed, any help will be appreciated, this is the jsfiddle http://jsfiddle.net/43jh9hzz/, and if you check the console log you will see the values.
This is the Js:
var json='';
var property_set = new Set();
function iterate(obj, stack) {
json="<ul>";
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property], stack + '.' + property);
}
else {
// console.log(property);
property_set.add(property);
json+="<li>";
if(typeof obj[property] !== "number") {
json+="<li>"+obj[property]+"</li>";
console.log(obj[property]);
}
}
} json += "</li>";
}
}
var listEl = document.getElementById('output');
iterate(jsonObj)
And this is the json format:
var jsonObj =
{
"level_1": [
{
"level_1_name": "CiscoSingaporeEBC",
"level_2": [
{
"level_2_name": "Khoo Tech Puat",
"level_2_id": 2222,
"level_3": [
{
"name": "Boon Leong Ong",
"id": 6919
},
{
"name": "Kiat Ho",
"id": 6917
},
{
"name": "Overall Experience",
"id": 6918
}
]
}
]
},
{
"level_1_name": "CiscoLondonEBC",
"level_2": [
{
"level_2_name": "Bernard Mathews Ltd.",
"level_2_id": 2367,
"level_3": [
{
"name": "Barry Pascolutti",
"id": 7193
},
{
"name": "Kathrine Eilersten",
"id": 7194
},
{
"name": "Martin Rowley",
"id": 7189
}
]
},
{
"level_2_name": "FNHW Day 1",
"level_2_id": 5678,
"level_3": [
{
"name": "Jurgen Gosch",
"id": 7834
},
{
"name": "Overall Experience",
"id": 7835
}
]
},
{
"level_2_name": "Groupe Steria Day 1",
"level_2_id": 2789,
"level_3": [
{
"name": "Adam Philpott",
"id": 7919
},
{
"name": "Pranav Kumar",
"id": 7921
},
{
"name": "Steve Simlo",
"id": 7928
}
]
}
]
}
]
};
enter code here
I'm not sure if I am interpretting your request correctly, but I think this is what you want: http://jsfiddle.net/mooreinteractive/43jh9hzz/1/
Basically, you are calling the iterate function to run, but then that's it. The function actually needs to also return the value it generates.
I've added to the end of the function, after the for loop completes:
return json;
Do now the function returns the value it generated, but there are some other issues too. When you recursively call the iterate function again inside the iterate function, you actually want to add what it returns to the current json string housing all of your returned value.
So on that line I changed it from:
iterate(obj[property], stack + '.' + property);
to
json += iterate(obj[property], stack + '.' + property);
Now that other value will come back as well inside the main list you were creating in the first run of the function. Ok so that's pretty close, but one more small thing. I think when you added additional surrounding LI, you actually wanted to do an UL. I changed those to ULs and now I think the result is like a UL/LI list representing the text parts of the JSON object.
Again, that may not be exactly what you were after, but I think the main take away is using the function to return the value, not just generate it, then do nothing with it.

Using jQuery $.each with Json erroring with 1 result

Basically I am transforming a JSON result into html and using $.each it iterate through multiple keys. For example, I am pulling back facebook posts and iterating through the likes in that post.
The problem lies in the fact that when there are multiple "likes" everything works great! although when there is only 1 "like" the "source" key is removed from the result set and my javascript breaks because I expect it to be there. Any idea why the $.each is skipping a level for single nodes? The following is my code:
* JQUERY **
$.each(post.likes.item, function(i, like){
$(currentpost).find('div.cc_likes').append(like + ',');
console.log(like)
});
* JSON RESULT **
* Single Like
likes": {
"item": {
"source": {
"cta": "Mary Smith",
"url": "http:\/\/www.facebook.com\/",
"photo": {
"image": "https:\/\/graph.facebook.com\/"
}
}
},
Result in console:
Object
cta: "MaryAnn Smith"
photo: Object
url: "http://www.facebook.com/"
* Multiple Likes
"likes": {
"item": [
{
"source": {
"cta": "Bobby Carnes Sr.",
"url": "http:\/\/www.facebook.com",
"photo": {
"image": "https:\/\/graph.facebook.com\"
}
}
},
{
"source": {
"cta": "Jenna Purdy",
"url": "http:\/\/www.facebook.com\",
"photo": {
"image": "https:\/\/graph.facebook.com\"
}
}
},
{
"source": {
"cta": "Kevin Say",
"url": "http:\/\/www.facebook.com\",
"photo": {
"image": "https:\/\/graph.facebook.com\"
}
}
}
],
"count": "10",
"count_display": "10"
},
Result in console:
Object
source: Object
cta: "Kevin Smith"
photo: Object
url: "http://www.facebook.com/"
Since $.each() needs an array or array like object as argument, before using the object post.likes.item check if it is an array of not.
Following code will always pass an array to jQuery -
$.each([].concat(post.likes.item), function(i, like){
$(currentpost).find('div.cc_likes').append(like + ',');
console.log(like)
});
Explanation
[] is an empty array in JavaScript. Every array in JavaScript has a concat method.
[].concat(obj) concats obj to the empty array and returns an array.
if obj is not an array, result is [obj] which is an array with one item.
if obj is an array, then result is a deep copy of obj which is already an array.
More about concat method
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback.call( obj[ i ], i, obj[ i ] );
if ( value === false ) {
break;
}
}
} else {
for ( i in obj ) {
value = callback.call( obj[ i ], i, obj[ i ] );
if ( value === false ) {
break;
}
}
}
That is the jquery code being run on your JSON return. What's happening is, when you are looking at multiple results, it is looping through the array, return each base level object. However, when you are running it on a single return, it is looping through the object properties(in this case, "source"), and returning the value of that property.
You have two choices here. You can either make sure single items are still put in an array, or you can do a check for single items on the client side. The way Moazzam Khan suggests is the best way to do it in most cases.

Getting JSON object values by name

I have a valid JSON object like this:
{
"reasons": {
"options": [
{
"value": "",
"label": "Choose a reason",
"selected": true,
"requiresValidation": false
},
{
"value": "small",
"label": "Too little",
"selected": false,
"requiresValidation": false
},
{
"value": "big",
"label": "Too big",
"selected": false,
"requiresValidation": false
},
{
"value": "unsuitable",
"label": "I don't like it",
"selected": false,
"requiresValidation": true
},
{
"value": "other",
"label": "Other",
"selected": false,
"requiresValidation": true
}
]
}
}
and I have a variable which stores one value (e.g. unsuitable) of an option available in options.
How can I retrieve the value of requiresValidation field for the value stored in the variable without having to loop through all of the objects values inside options?
For instance, if the var content is other I'd like to access to requireValidation field of the object whose value is other (which is true). Is it possible?
Thank you.
You aren't really dealing with JSON here, you are dealing with a JS object. JSON is just a format for sending JS objects.
options is an array. The only way to access it is by index, which means you will have to do a search, one item at a time. There are functions, such as indexOf() which will return the first index of a value in an array, however, you have an array of objects, so that will not work in this case. (And internally, it is still doing a search).
function getReqVal(val) {
for (var item in mydata.reasons.options) {
if(item.value == val) {
return item.requiresValidation;
}
}
}
getReqVal("other");
The caveat is that this will return on the first one, so if you have more than one other, you won't get them.
If the options are indeed unique values, I would rearrange your object to be an associative array, with the keys being the "value" items, and the values being an object with the rest of the data:
{
"reasons": {
"options": {
"" : {
"label": "Seleziona una voce",
"selected": true,
"requiresValidation": false
},
"small" : {
"label": "Too little",
"selected": false,
"requiresValidation": false
},
"big" : {
"label": "Too big",
"selected": false,
"requiresValidation": false
},
"unsuitable" : {
"label": "I don't like it",
"selected": false,
"requiresValidation": true
},
"other" : {
"label": "Other",
"selected": false,
"requiresValidation": true
}
}
}
}
If you are (or could be) using underscore.js you could use the find method:
var item = _.find(myObj.reasons.options,
function(option){ return option.value == 'some value' });
Assuming you can't change the JSON structure itself (because perhaps you're getting it from an external source?), you can read it into a new object of your design per Marc B's suggestion. Ideally, this new object would let you index into your options array using the value key. Let's do that:
function MyOptions(optionsJSON) {
this.original_json = optionsJSON;
this.length = optionsJSON.reasons.options.length;
var original_options = optionsJSON.reasons.options;
for(var i = 0; i < this.length; i++)
this[original_options[i].value] = original_options[i];
}
var my_opts = new MyOptions(original_JSON);
var item_requiresValidation = my_opts["unsuitable"].requiresValidation;
console.log(item_requiresValidation); // should log "true"
The trade-off here is that your code will need to loop through the entire options array once, but after that you can index into the objects using the value key without searching. Validate with this jsfiddle.
You could use array filter. Some variation of this:
var $reasons = //Your JSON
function checkVal(element, index, array) {
return (element.value == "other");
}
var filtered = $reasons.reasons.options.filter(checkVal);
alert(filtered[0].requiresValidation);
Or jQuery grep might help you with the filter without looping: http://api.jquery.com/jQuery.grep/

Categories