Setting values in JSON to default JSON items - javascript

I am on a Dojo app, is there any special JS parser which enables me default values within JSON data ?
Example, I'd like to set "maxHeadingLength" in item[1] to the value in item[0].
{
items:[
{
"class": "pmedia.types.PMPlatformRenderConfiguration",
"listItemHeight": "70",
"listItemIconHeight": "60",
"maxDesktopItemsWithBannerP": "9",
"maxDesktopItemsWithBannerL": "9",
"platform": "Default",
"maxHeadingLength":
{
P:300,
L:400
}
},
{
"class": "pmedia.types.PMPlatformRenderConfiguration",
"listItemHeight": "70",
"listItemIconHeight": "60",
"platform": "IPAD",
"maxHeadingLength": "Default"
},
Something like this would good too :
"maxHeadingLength": "this.items[0].maxHeadingLength"
Thanks
Update, It seems I can and need to precise the question a bit better now.
I'd like to write any string expression into the pure JSON string data(file), as string of course and evaluate the data within the same data set without using "eval".
Thanks to all !

You can either do this in a backend process or using a front end process as you process the JSON.
Let's assume you're wanting to do it in the front end using JS, I would suggest firstly setting the items[0].maxHeadingLength as a var, like so:
var defaultMaxHeadingLength = items[0].maxHeadingLength;
And then as you loop through your JSON you can check whether the maxHeadingLength attribute has a value or not and default it, like so:
var item, i;
for ( i = 0; i < items.length; i++ )
{
item = items[ i ];
item.maxHeadingLength = item.maxHeadingLength ? item.maxHeadingLength : defaultMaxHeadingLength;
}

Here's an idea of one way to do it (if I understand what you're trying to do):
var defaultItem = {
"maxHeadingLength": {
P: 300,
L: 400
}
};
var jsondata = {
items: [
{
"class": "pmedia.types.PMPlatformRenderConfiguration",
"listItemHeight": "70",
"listItemIconHeight": "60",
"platform": "IPAD",
"maxHeadingLength": this.defaultItem.maxHeadingLength
}
]
};
alert(jsondata.items[0].maxHeadingLength.L);
//returns 400
Basically you have a default item separate to all your other items, allowing you to refer to the defaults in the main data.
I don't think you can use this.jsondata from within the same object, since it hasn't finished being created yet (but I could be wrong).

Related

Adding a new object into a nested array

I want to add a new object for each nested array. I'm calling this function any time I add a product to my orderintake:
add2order(productID, productName, productRatePlans) {
this.orderIntake.push({ productID, productName, productRatePlans });
let i = 0;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges.forEach(element => {
i++;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].quantity = this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].defaultQuantity;
});
}
this is an example response from the server:
{
"id": "8adc8f996928b9a4016929c59b943a8f",
"sku": "SKU-00006778",
"Partner_Account_ID__c": null,
"productRatePlans": [
{
"id": "8adce4216928c28d016929c59bff3372",
"status": "Active",
"name": "Enterprise",
"description": null,
"effectiveStartDate": "2016-02-26",
"effectiveEndDate": "2029-02-26",
"productRatePlanCharges": [
{
"id": "8adc8f996928b9a4016929c59d183a92",
"name": "USAGE_COUNTER_2",
"type": "Usage",
"model": "Volume",
"uom": "Each",
"pricingSummary": [
"Up to 5000 Each: USD0 flat fee"
],
"pricing": [
{
...
}
],
"defaultQuantity": null,
"applyDiscountTo": null,
"discountLevel": null,
"discountClass": null,
...
"financeInformation": {
..,
}
}
]
}
],
"productFeatures": [
{
...
}
]
}
The data is being retrived this way from an external REST backend so unfortunately I can't initialize the data including the new property...
so in every productRatePlanCharges there should be 1 new object 'quantity'.
How can I add this field to every productRatePlanCharges?
Right now I'm getting: ERROR
TypeError: Cannot read property 'productRatePlanCharges' of undefined
And how can I make sure I'm always adding this to the last orderIntake element? Don't mind productRatePlans there is only 1 in each orderintake...
thanks for your support!
Here you have to create productDetails object with inititalised array like below so that you won't get the error.
add2order(productID, productName, productRatePlans) {
// Create object like below
let productDetails = { productID : productID, productName : productName, productRatePlans : productRatePlans
}
this.orderIntake.push(productDetails);
let i = 0;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges.forEach(element => {
i++;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].quantity = this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].defaultQuantity;
});
}
Hope this will help!
as you used Angular you probably use Typescript too. I recommend that you create a model like your incoming model and there define your quantity: number inside productRatePlanCharges object. then map the incoming data to your own model. therefore you will have a quantity=0 in your model that you can change it later in a loop.
If you want to continue with your own way take a look at this:
Add new attribute (element) to JSON object using JavaScript
there is no problem to add an element to current model almost like you did, and the problem might be somewhere else as your error refers to existence of productRatePlanCharges!
as you used forEach I prefer to use that 'element' and double iterating with i++; is not a good idea to me.
this might be better:
element.quantity = element.defaultQuantity;

Angular ng-model & filter using nested data vs top layer

I have a list of data displayed on my page that is broken down into divs. Each div represents an array of data in my object, pretty common.
I am trying to add a text box to my page where I can filter out the data and it will narrow down the results shown on the page as more data is entered into the text box.
For that, I added a filter on my ngFor like so: *ngFor="let x of data | filter: filterString".
My text-box then uses ngModel to filter that data down:
<input type="text" class="form-control" placeholder="Filter..." name="ruleFilter" id="ruleFilter" [(ngModel)]="filterString" (keyup)="onFilter($event)">
The issue I am having is that the filter seems to only be working with the top layer of data in my object. For example, the data below is what one of the results looks like in my ngFor loop. I can search Omaha just fine since its in the top level and it filters it down correctly.
However, If I look for something like Campus which is nested inside Attribute, it doesn't find it in the filter and no results are shown.
{
"RuleParentID": "618",
"RuleVersionID": "18",
"MappedValue": "1",
"ProcessingOrder": 1,
"KeyID": "1",
"Value": "Omaha",
"IsRuleRetired": "0",
"UserImpactCount": "0",
"Attribute": [
{
"AttributeID": "6",
"AttributeName": "Campus",
"Operator": {
"OperatorID": "3",
"OperatorName": "In List",
"SqlOperator": "IN"
},
"AttributeValue": [
{
"AttrValue": "1",
"Value": "Omaha",
"IsValueRetired": "0",
"disabled": "False"
}
]
},
{
"AttributeID": "14",
"AttributeName": "Grade",
"Operator": {
"OperatorID": "1",
"OperatorName": "Greater Than",
"SqlOperator": ">"
},
"AttributeValue": [
{
"AttrValue": "14",
"Value": "14",
"IsValueRetired": "0",
"disabled": "False"
}
]
}
]
}
Is there any way to have the model look at all layers of the object for my binding instead of just the top layer (which I only assume its doing at this time) ?
Update: Here is a plunker of what my basic setup is like: https://plnkr.co/edit/eywuWmPRseUkmVPbTEOf?p=preview
You will see the data model that searches by the top level properties just fine, but when I search for something nested, I don't get any results back.
If I understand well the question, I think that to flat the data will help you:
var flattenObject = function(ob) {
var toReturn = {};
for (var i in ob) {
if (!ob.hasOwnProperty(i)) continue;
if ((typeof ob[i]) == 'object') {
var flatObject = flattenObject(ob[i]);
for (var x in flatObject) {
if (!flatObject.hasOwnProperty(x)) continue;
toReturn[i + '.' + x] = flatObject[x];
}
} else {
toReturn[i] = ob[i];
}
}
return toReturn;
};
let newData = flattenObject(data);
Code source: https://gist.github.com/penguinboy/762197
To achieve expected result , use below option
1.In your component below variable
jsonVal:any=JSON; // for using JSON.stringify and indexOf
Use *ngIf to filter value from input with indexOf
<input type="text" [(ngModel)]="filterString">
<div *ngFor="let data of result">
<div *ngIf="jsonVal.stringify(data).indexOf(filterString)!= -1">{{data| json}}</div>
</div>
code sample for reference - https://stackblitz.com/edit/angular-ht2afv?file=app/app.component.html
Just for testing , I have added another Object with Campus2 and Omaha2
When filtering on a nested property of data you can use the map function or similar.
This will be in your component and not the template. Filtering using pipes in the template is discouraged by the Angular team for performance reasons.
Instead I would do something like this:
const data = [{//your data}]
let filteredData = [];
data.map(val => {
if (val.Attribute.filter(name => name.AttributeName === "Foo").length > 0) {
filteredData.push(val)
}
});
I am assuming your data is an array of objects.
Beware I am mutating my data object. To avoid this you do this:
const data = [{//your original data}]
const dataToFilter = JSON.Parse(JSON.stringify(data))
This will make copy of your data without references to your original object. Useful if you want to clear your filter. Not useful if your data object contains functions.
On re-reading your question I think this is not the solution you were looking for but rather a method to look anywhere in the data. For this you should probably flatten your data as suggested by Zelda7. Another approach would be to extend a filtering method to explicitly filter on all relevant fields.

JSON, node.js: access classes via its name (String)

Here's my situation, I have a JSON that looks somewhat like this:
{
"items": [{
"type": "condition",
"data": {
"type": "comparison",
"value1": {
"source": "MyType1",
"component": "Attribute1"
},
"value2": {
"source": "MyType2",
"component": "Attribute2"
},
"operator": "gt"
}
},
{
"type": "then",
"data": {
"result": "failed",
"message": "value1 is too high"
}
}
]
}
and would want it to translate to:
if (MyType1.Attribute1 > MyType2.Attribute2) {
result = "failed";
console.log("value1 is too high");
}
Now my problem is, I don't know how I would translate the entries of value1 and value2 to actual code, or rather, how I could access the Object MyType1(maybe through something like getAttribute("MyType1")).
Since I am going to have a whole bunch of sources which each have different components, I cant really write a huge dictionary. Or I would like to avoid it.
The goal is to allow creating if - then - statements via some interactive UI, and I figured it'd be best to save that code as .json files. (Think rule management system).
So, TL,DR, How would I access a Class Attribute this.MyType, if I only have a String MyType to go from? And how would I access the value this.MyType.MyValue, if I get another String MyValue?
Thanks in advance.
Edit:
I'd really like to avoid using eval, for obvious reasons. And if I have to - I guess I would need to create Dictionaries for possible JSON Values, to validate the input?
You need some kind of parser. At first we need some way to store variables and maybe flags:
const variables = {};
var in = false;
Then we go through the code and execute it:
for(const command of items){
switch( command.type ){
case "condition":
//...
case "then":
//...
}
}
To access a variable we can simply do
var current = variables[ identifier ];
To store its the other way round:
variables[ identifier ] = current;

How to filter the json data using Underscore

I am new to Underscore. I have a json array which is pasted below. If I want to filter the below array based on developed field having "yes" as value. How can I do using Underscore.js. Currently I am iterating over the content of array and manually selecting the objects and populating in into another array. Is there a better way to do using Underscore?
{
"content": [
{
"stateName": "Karnataka",
"population": 1000000,
"developed": "yes"
},
{
"stateName": "Kerala",
"population": 1000000,
"developed": "yes"
},
{
"stateName": "Tamilnadu",
"population": 1023213213213,
"developd": "yes"
},
{
"stateName": "Bsadasd",
"population": 1023213213213,
"developed": "no"
}
]
}
Not sure if I'm missing something here but the obvious underscore function is filter:
var developedStates = _.filter(data.content, function(state){
return state.developed == 'yes';
});
You can filter an array on its properties by using _.where :
where _.where(list, properties)
Looks through each value in the list, returning an array of all the values that contain all of the
key-value pairs listed in properties.
which leads to
var filtered = _.where(data.content, {developed: "yes"});
and a demo http://jsfiddle.net/nikoshr/NExZC/
As far as I know, underscore doesn't have a way to help you with this task. You can do this without using underscore with a native Javascript method called select:
var filteredArray = originalArray.select(function(item, index) {
return item.developed == "yes"; // Include this item if it has a proper value
});
Note that the select method is only available in browsers that support EcmaScript 5 specifications, so for older browsers you will need some supporting library like es5-shim.

How to manipulate JSON object to remove root key within Javascript?

I have a json url that returns data in the format
{
"photos" : [
{
"id": 1, "image":"https://path/to/my/image/1.jpg"
},
{
"id": 2, "image":"https://path/to/my/image/2.jpg"
}
]
}
I'm using the json in a javascript function, and need to manipulate it to remove the root key. i.e. I want something that looks like
[
{
"id": 1, "image":"https://path/to/my/image/1.jpg"
},
{
"id": 2, "image":"https://path/to/my/image/2.jpg"
}
]
I've been hacking around with various approaches, and have referred to several similar posts on SO, but nothing seems to work. The following seems like it should.
var url = 'http://path/to/my/json/feed.json';
var jsonSource = $.getJSON( url );
var jsonParsed = $.parseJSON(jsonSource);
var jsonFeed = jsonParsed.photos
What am I doing wrong?
A couple of issues there.
That's invalid JSON, in two different ways. A) The : after "photos" means that it's a property initializer, but it's inside an array ([...]) when it should be inside an object ({...}). B) There are extra " characters in front of the images keys. So the first thing is to fix that.
You're trying to use the return value of $.getJSON as though it were a string containing the JSON text. But $.getJSON returns a jqXHR object. You need to give it a success callback. That callback will be called with an object graph, the JSON is automatically parsed for you.
Assuming the JSON is fixed to look like this:
{
"photos": [
{
"id": 1,
"image": "https://path/to/my/image/1.jpg"
},
{
"id": 2,
"image": "https://path/to/my/image/2.jpg"
}
]
}
Then:
$.getJSON(url, function(data) {
var photos = data.photos;
// `photos` now refers to the array of photos
});

Categories