I have a JSON Object graph that looks like this (note there is only 1 array in the object called lineItems:
{
"salesOrderUid": 52,
"orderNumber": "1428002206349",
"billToCity": "Golden",
"billToFirstName": "Duke",
"billToLastName": "Developer",
"shipToStreetNumber": "12345",
"shipToUnitNumber": null,
"shipToZipCode": 80401,
"promoCode": "Test",
"lineItems": [
{
"salesOrderLineUid": 59,
"salesOrderUid": 52,
"extendedPrice": 50,
"itemQuantity": 10,
"itemPrice": 5,
"catalogItem": {
"catalogItemUid": 1,
"itemPrice": 5,
"catalog": {
"catalogUid": 1,
"validFrom": 1420095600000,
"validThrough": 1435644000000
},
"item": {
"itemUid": 1,
"productCategoryUid": 1,
"productDescription": "Product used for testing",
"productName": "Test"
}
},
"shipmentUid": null
}
]
}
I iterate over lineItems like so:
<tr ng-repeat="salesOrderLineItem in salesOrder.lineItems">
<td>{{salesOrderLineItem.catalogItem.catalog.productName}}</td>
<td>{{salesOrderLineItem.itemQuantity}}</td>
<td>{{salesOrderLineItem.itemPrice | currency}}</td>
<td>{{salesOrderLineItem.extendedPrice | currency}}</td>
</tr>
The "first level" properties are displayed just fine. (itemQuantity, itemPrice and extendedPrice) But nothing gets displayed for the nested property called catalogItem.catalog.productName.
The JSON object reflected above came directly out of the Developer Tools console so it's clear that the contents are there. And the catalogItem property is not an array so I should be able to chain object property references, shouldn't I?
I've seen many questions posted related to accessing nested JSON but they seem to all have nested arrays in the JSON...which is not the case here.
Thanks in advance
catalog does not contain a field called productName. Did you mean to use item instead of catalog?
Looks to me that 'productName' is nested under 'item', not 'catalog'.
Change the line to be
<td>{{salesOrderLineItem.catalogItem.item.productName}}</td>
And that should be what you are looking for?
Related
I have file that is list of JSON objects. It looks like this :
[
{
"id": 748,
"location": {
"slug": "istanbul",
"parent": {
"id": 442,
"slug": "turkey"
}
},
"rank": 110
},
{
"id": 769,
"location": {
"slug": "dubai",
"parent": {
"id": 473,
"slug": "uae"
}
},
"rank": 24
}
]
I want to create a list of hotel parent names, so i write this code to do this, I read the JSON file and assigned it to a variable, that part is correct. But look at this code :
with open('hotels.json', 'r', encoding="utf8") as hotels_data:
hotels = json.load(hotels_data)
parents_list = []
for item in hotels:
if item["location"]["parent"]["slug"] not in parents_list:
parents_list.append(item["location"]["parent"])
when i run this code, i give this error :
if item["location"]["parent"]["slug"] not in parents_list:
TypeError: 'NoneType' object is not subscriptable
This code does not work, so I tried to print the JSON objects so I wrote this in the loop:
print(item["location"]["parent"]["slug"])
This code prints the values I want, but also give me the exact same error.
thank you for any help.
I tried running the code and it seems to be working fine with your dataset.
However, instead of opening the file to read the data, I just assigned hotels with your dataset, hotels = [...].
The result I got was this:
[{'id': 442, 'slug': 'turkey'}, {'id': 473, 'slug': 'uae'}]
What is your result if you print hotels, is it the same as you shown here?
If you actually have a lot more data in your dataset, then I can presume that some of the dictionaries don't contain item["location"]["parent"]["slug"]. If that is the case, you should skip those by checking if that element exists in each item first before reading off from the parents_list.
For example:
try:
item["location"]["parent"]["slug"]
except (KeyError, TypeError) as e:
pass
else:
if item["location"]["parent"]["slug"] not in parents_list:
parents_list.append(item["location"]["parent"])
I cannot replicate the same error as you. The only thing that I can think of is that the last item in each object in the JSON shouldn't have a comma after it. See if that fixes your error
Is there a way to deserialize a JSON that includes references to objects that already exist inside it using typescript?
For example we have a grand parent "Papa" that is associated with two parents "Dad" and "Mom" that they have together two children, the json looks like:
{
"id_": 1,
"name": "Papa",
"parents": [
{
"#class": "com.doubleip.spot.mgmt.test.domain.model.Parent",
"id_": 1,
"name": "Dad",
"children": [
{
"#class": "com.doubleip.spot.mgmt.test.domain.model.Child",
"id_": 1,
"name": "Bob"
},
{
"#class": "com.doubleip.spot.mgmt.test.domain.model.Child",
"id_": 2,
"name": "Trudy"
}
]
},
{
"#class": "com.doubleip.spot.mgmt.test.domain.model.Parent",
"id_": 2,
"name": "Mom",
"children": [
1,
2
]
}
]
}
You may see that the children of Mom are just inserted as the value of their "id_" field. This happens due to JsonIdentityInfo used in Java and fasterxml library.
So we face problem in front-end deserialisation where we use typescript angular and primeng in order to visualise our data.
So we face problem in front-end deserialisation
you need to write most of the code yourself (or generate it using more code from your Java code).
That said, there are a few hydration helpers. I recommend : https://github.com/mobxjs/serializr
Please help me in parsing this Json sample as I'm not able to parse it because of the complexity of it as well as different objects inside it. I'm able to parse Json when a list of same objects & same structure but not like the one below.
[
{
"notificationBrowserHead":
{
"notificationId": 4,
"notificationType": "NEW_PRODUCT",
"creationTime": 1421933381000,
"notificationNormalUserId": 4,
"notificationViewed": false
},
"brandIdAndNameHolder":
{
"brandId": 1,
"name": "B1"
},
"brandLogo": null,
"productIdAndNameHolder":
{
"productId": 1,
"name": "JK product1"
}
},
{
"notificationBrowserHead":
{
"notificationId": 2,
"notificationType": "USER_INT_COMMENT",
"creationTime": 1421924403000,
"notificationNormalUserId": 2,
"notificationViewed": false
},
"uploadId": 22,
"uploadThumbnail": "/mediaUrl/location/thumbNail",
"uploadDescription": "upload 1 location desc",
"notificationCreator":
{
"normalUserId": 90,
"displayName": "amit"
},
"uploadRemoved": false
},
{
"notificationBrowserHead":
{
"notificationId": 1,
"notificationType": "NEW_LOCATION_VOTE",
"creationTime": 1421924403000,
"notificationNormalUserId": 1,
"notificationViewed": false
},
"locationIdAndNameHolder":
{
"locationId": 11,
"name": "Current King JK"
},
"locationLogo": null
}
]
Any help would be truly appreciated.
I presume that you receive different set of json properties when your NotificationType varies.
Solution 1:
Define all your members(the collection of all your properties that you receive for different types of notification) in a Class and use it for DeSerialization, so that the unwanted properties for your particular notification type will be null.
Solution 2:
Parser manually. Newtonsoft json documentation here
Make class "Notifications (or something)" and put inside everything you got back from json2csharp.com site, then use this framework http://www.newtonsoft.com/json to deserialize data as you download it from server and you should be able to get notificationType by Object.Notificationbrowserhead[x].notificationType or similar.
I am new to Ember and JSON. I want to parse a JSON object that is below with typeahead library
and access nested object values by searching their keys.
I have this Json format:
return [
{
"id": 1,
"category_name": "Supermarket",
"category_description": "SUPER MARKET",
"image_url": "",
"merchants": [
{
"name": "CARREFOUR",
"id": 12,
"merchant_type_id": 1,
"merchant_type_description": "Gold",
"merchant_redeption_rate": 0.002500,
"image_url": "https://jpg",
"branches": [
{
"id": 123456,
"latitude": 37.939483,
"area": "ΑΓ. ΔΗΜΗΤΡΙΟΣ",
"zip": "12345"
},
{
"id": 4567890,
"longitude": 23.650622,
"area": "ΑΓ. ΙΩΑΝΝΗΣ ΡΕΝΤΗΣ",
"zip": "12345"
}
]
},
{
"name": "CAFCO",
"id": 13,
"merchant_type_id": 3,
"merchant_type_description": "None",
"merchant_redeption_rate": 0.002500,
"image_url": "https:.jpg",
"branches": [
{
"id": 127890,
"latitude": 38.027870,
"area": "ΠΕΡΙΣΤΕΡΙ",
"zip": "12345"
}
]
}
]
},
{
"id": 2,
"category_name": "Πολυκαταστήματα",
"category_description": "ΠΟΛΥΚΑΤΑΣΤΗΜΑ",
"image_url": "",
"merchants": [
{
"name": "AGGELOPOYLOS CHR.",
"id": 15,
"merchant_type_id": 2,
"merchant_type_description": "Silver",
"merchant_redeption_rate": 0.002500,
"image_url": "https://www.nbg.gr/greek/retail/cards/reward-programmes/gonational/PublishingImages/aggelopoulos.jpg",
"branches": [
{
"id": 234780,
"latitude": 35.366118,
"longitude": 24.479461,
"address": "ΕΘΝ. ΜΑΚΑΡΙΟΥ 9 & ΕΛ. ΒΕΝΙΖΕΛΟΥ 1",
"area": "Ν. ΦΑΛΗΡΟ",
"zip": "12345"
}
]
}
]
}
];
--------------------------Updated----------------------------
For example, i want to search using typeahead the name of merchants and when the letter we write to search matches the name of merchants it will appear the corresponding category_name and backwards.
Example -> when i keyboard the s it will appear :
Category : Supermarket,
Name: CARREFOUR
Name: CAFCO
And the same output on the dropdown of search when i keyboard the letter c.
Any help?
New Jsbin example
The simplest way (in my mind) to get this to work is to create a computed property that will contain an array of latitudes. But how do we get there?
To get to latitude, you need to go through array of merchants and then array of branches. Being that this will be across multiple elements, you are going to end up with "array of arrays" type data structure, which is annoying to deal with. So, to simplify this, we can create a simple flatten function as follows:
flatten: function(origArray){
var newArr = [];
origArray.forEach(function(el) {
el.forEach(function(eachEl){
newArr.push(eachEl);
});
});
return newArr;
},
In addition to our function above, Ember already provides us with many other useful functions that can be used on arrays (see here). One of those is mapBy(property) which transforms an array into another array only keeping the values of the property we specified.
So, to create a lats (for latitudes) property, we can just do this:
lats: function(){
var merchantsArr = this.get('model').mapBy('merchants');
merchantsArr = this.flatten(merchantsArr);
var branchesArr = merchantsArr.mapBy('branches');
branchesArr = this.flatten(branchesArr);
return branchesArr.mapBy("latitude").compact();
}.property('model')
Above, I am basically using mapBy, flatten (see above) and compact which
Returns a copy of the array with all null and undefined elements removed.
Once you have the lats property with all the necessary data, the rest is easy.
Your call to component becomes:
{{x-typeahead data=lats name='category_name' selection=myColor}}
Note lats instead of model you originally were passing into the component.
And now, to access the value of data property in the component, you do
`this.get('data')`
which you can just pass in as the source like so:
source: substringMatcher(self.get('data'))
Working solution here
Update
Updating my answer based on your updated question.
OK, so this is getting a little more complicated. You now need more than just one property (latitude) from the object. You need category_name and merchant name.
In addition to mapBy, which just grabs one property out of array, Ember also has map which lets you transform the array into pretty much anything you want to:
lats: function(){
var merchantsArr = this.get('model').map(function(thing){
var category_name = thing.category_name;
return thing.merchants.map(function(merchant){
return {
"name": merchant.name,
"category": category_name
};
});
});
merchantsArr = this.flatten(merchantsArr);
return merchantsArr;
}.property('model')
The code above looks complicated, but it's basically just returning an array of top level objects' merchants accompanied by category_name. Since this is an array of arrays, we will need to flatten it.
Then, inside the component, we need to keep in mind that we are not just passing in an array of strings, but rather we are passing in an array of objects. Therefore, we need to look through object's properties (name and category) for a match
$.each(strs, function(i, str) {
if (substrRegex.test(str.name) || substrRegex.test(str.category)) {
matches.push(str);
}
});
Lastly, to actually display both category and merchant name, you need to tell Typeahead how to do that:
templates: {
suggestion: Handlebars.compile('<p>{{name}} – {{category}}</p>')
}
Working solution here
there!
I´ve one column in my jqGrid that is empty.
But i checked the object on chrome console and thats fine.
colModel definition
colModel:[
{name:'id',index:'id', width:55,editable:false,editoptions:{readonly:true,size:10},hidden:true},
{name:'firstName',index:'firstName', width:100,searchoptions: { sopt: ['eq', 'ne', 'cn']}},
{name:'lastName',index:'lastName', width:100,editable:true, editrules:{required:true}, editoptions:{size:10}},
{name:'books[0].nome',index:'books[0].nome', width:100,editable:true, editrules:{required:true}, editoptions:{size:10}},
{"formatter":"myfunction", formatoptions:{baseLinkUrl:'/demo/{firstName}|view-icon'}}
]
JSON response
{
"total": "10",
"page": "1",
"records": "3",
"rows": [
{
"id": 1,
"firstName": "John",
"lastName": "Smith",
"books": [{"nome": "HeadFirst"}]
},
{
"id": 2,
"firstName": "Jane",
"lastName": "Adams",
"books": [{"nome": "DalaiLama"}]
},
{
"id": 35,
"firstName": "Jeff",
"lastName": "Mayer",
"books": [{"nome": "Bobymarley"}]
}
]
}
chrome console inspect object
rowdata.books[0].nome
"HeadFirst"
Any one know where theres are possibles trick?
Tks!
You should use as the value of name property of colModel only the names which can be used as property name in JavaScript and as CSS id names. So the usage of name:'books[0].nome' is not good idea.
To solve your problem you can use jsonmap. For example you can use dotted name conversion:
{name: 'nome', jsonmap: 'books.0.nome', ...
In more complex cases you can use functions as the value of jsonmap. For example
{name: 'nome', jsonmap: function (item) {
return item.books[0].nome;
}, ...
You can find some more code examples about the usage of jsonmap in other old answers: here, here, here, here, here.
name is intended to be a unique name for the row, not a reference to a JSON object. From the jqGrid colModel options documentation:
Set the unique name in the grid for the column. This property is required. As well as other words used as property/event names, the reserved words (which cannot be used for names) include subgrid, cb and rn.
You can also observe how .name is used within grid.base.js - for example:
var nm = {},
...
nm = $t.p.colModel[i].name;
...
res[nm] = $.unformat.call($t,this,{rowId:ind.id, colModel:$t.p.colModel[i]},i);
Anyway, to get back to your question I think you will have better luck by passing down the book name directly - as strings and not objects - and referencing it by name as something like bookName.