Merge particular part of JSON together - javascript

I want to merge particular part of a JSON code with another JSON. To clarify, please refer to example below:
JSON 1:
{"metadata": {
"userName": "Batman",
"userId" : "402",
"config":{
"a" : "some text here",
"b" : "some other text here"
}
}}
JSON 2:
{"metadata": {
"userName": "Superman",
"userId" : "102",
"config":{
"a" : "Overwrite Text 1",
"b" : "Overwrite Text 2"
}
}}
Now, I want to overwrite ONLY config part JSON 1 with JSON 2 So that JSON 1 will become:
{"metadata": {
"userName": "Batman",
"userId" : "402",
"config":{
"a" : "Overwrite Text 1",
"b" : "Overwrite Text 2"
}
}}
I have already tried using loop but I want to figure out if there is more efficient way to code this up. I am using Angular and pure JS.

You can try Object.assign - Mozilla foundation doc
var obj1 = JSON.parse(json1);
var obj2 = JSON.parse(json2);
Object.assign(obj1.metadata.config,obj2.metadata.config);

Its really simple:
json1.metadata.config = json2.metadata.config;
You overwrite its config data with the config from the other json object.
Let me know if you want me to elaborate more.

json1.metadata.config = json2.metadata.config;
should be enough.
You've got to remember that modifiying json2.metadata.config will modify json1.metadata.config, this is a shallow copy.

Using Object.assign as Djave said is correct, but if you're not using ES6 and a transpiler you can take advantage of Angular itself and do a plain angular.copy:
var obj1 = JSON.parse(json1);
var obj2 = JSON.parse(json2);
obj1.metadata.config = angular.copy(obj2.metadata.config);
This way you will get the new JSON part copied and referenced on its own.

Related

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.

set json property depending on child property

I am creating this JSON object
{
"attachment": {
"type": "template",
"payload": {
"template_type": "generic",
"image_aspect_ratio": "square"
"elements": [
new CreateBallon(results[rand])
]
}
}
}
I want to set the image_aspect_ratio in only if elements[0].someProp is present.
How can I do that?
Let's clear what JSON is. It is a textual notation for data. If you do anything with the object that involves code of Javascript don't call it JSON so, The object you're talking about is not a JSON but a JavaScript object created via object literal notation.
Now to answer your query, you can't refer to this object before you've fully initialized that object. So what you can do is initialize your object with some default value and then you should be able to edit any property based on the properties from the same object. Something like
var obj = {"property1" : "X", "property2" : ""};
Now you can update your object like
obj.property2 = obj.property1 =='yourCondition' ? 'NewValue' : obj.property2

Accessing data from json in Angularjs

I have a JSON object Like this-
[
{
"user": "A220",
"shorttext": "shanghai",
"reportedBy": "S,A",
"questions": "
[{\"question\":\"Q1\",\"is_mand\":\"0\",\"type\":\"text\",\"answer\":\"w\",\"ansYesOrNo\":false,\"ansDetails\":\"\"},{\"question\":\"Q2\",\"is_mand\":\"0\",\"type\":\"text\",\"answer\":\"ed\",\"ansYesOrNo\":false,\"ansDetails\":\"\"}]",
"notifno": "20143995",
"error": "",
"createdOn": "2015-09-09 13:08:36",
"Id": 0,
"$$hashKey": "object:89"
}
]
I need to access the 1st question of questions.Please i am not able to access it like this alert(obj.questions[0].question);
Here is a jsFiddle Link-LINK to Fiddle
The main problem is that the questions array inside the object, It is not an array. Is a Array convert to string, you must parse the questions to get the respective Json object with the data.
Here is your fiddle updated: http://jsfiddle.net/marduke182/w02ck9uw/1/
And the part of code important:
var questonObj = JSON.parse($scope.a[0].questions);
Use fromJson method this way:
angular.fromJson(a[0].questions)[0].question

How to get the name of the array in json data using JavaScript

I have a JSON object which comes back like this from a JavaScript API call:
{
"myArray": [
{
"version": 5,
"permissionMask": 1
},
{
"version": 126,
"permissionMask": 1
}
]
}
How can I access the name of the array (i.e myArray) in JavaScript. I need to use the name of the array to determine the flow later on.
Use getOwnPropertyNames to get a list of the properties of the object in array form.
Example:
var myObj = {
"myArray": [
{
"version": 5,
"permissionMask": 1
},
{
"version": 126,
"permissionMask": 1
}
]
},
names = Object.getOwnPropertyNames(myObj);
alert(names[0]); // alerts "myArray"
Note: If the object can have more than one property, like myArray, myInt, and myOtherArray, then you will need to loop over the results of getOwnPropertyNames. You would also need to do type-testing, as in if(names[0] instanceof Array) {...} to check the property type. Based on your example in your question, I have not fleshed all of that out here.
Object.keys(data)[0]
# => "myArray"
A terminology note: This solution assumes you have a JavaScript object. You might have a JSON string, in which case this is the solution:
Object.keys(JSON.parse(data))[0]
# => "myArray"
However, "JSON object", in JavaScript, is just one - the one I used just now, that has JSON.parse and JSON.stringify methods. What you have is not a JSON object except perhaps in a trivial interpretation of the second case, where all values in JavaScript are objects, including strings.
The other answers are good if you have no control over the return format.
However, if you can, I'd recommend changing the return format to put the important values you care about as actual values instead of keys to make it clearer. For example, something like this:
result =
{
"name: "myArray",
"value": [
{
"version": 5,
"permissionMask": 1
},
{
"version": 126,
"permissionMask": 1
}
]
}
Then, it's a lot clearer to reliably access the property you care about: result.name

stringify JSON reference name, not the referenced object

I have a JSON object like so, (this is an example)
house.keys = {
"key1" : "23456",
"key2" : "97543",
"key3" : "35493"
}
house.doors = [{
"name" : "Front door",
"lock key" : house.keys.key1
}, {
"name" : "Back door",
"lock key" : house.keys.key2
}
]
This object is stored in the DB as a string, and read and parsed() on page load. It will likely be edited by user interaction, then the altered object needs to be stringify()-ed and written back into DB. I've got everything working except for a problem in the stringify() function.
Instead of this:
"lock key" : house.keys.key1
I get this:
"lock key" : "23456"
How do I get the stringify() method to return the referenced object's name instead of the referenced object, itself.
I've looked into using a replacer function:
JSON.stringify(house, replacer); // Where replacer() returns 'something else' for "lock key", but I don't know what 'something else' is.
Thanks.
Just enclose the name in quotes so that it will be treated as a string and therefore, the value will not be parsed and put.
house.doors = [{
"name": "Front door",
"lock key": "house.keys.key1"
}, {
"name": "Back door",
"lock key": "house.keys.key2"
}]
This does appear to be the best solution to my problem. It did require a change to the code that was using the 'house' object.
Before, I was referencing the key as such:
var key1 = house.doors[0]["lock key"];
Now I have to use:
var key1 = house.doors[0]["lock key"];
var key1 = eval(key1);
(I believe I've written this right. My actual code is considerably different.)
All in all, an easier fix then the other solutions I was contemplating.

Categories