I want to serialize circular reference to JSON
This is the part generating the JSON array and it causes a circular reference because it creates a child inside an element and I want to display the result.
const mappedData = this.state.treeData
.filter(data => data.title === "Category")
.map(categ => {
const { id, title, children, subtitle, type } = categ;
function getChildren(children) {
return children
? children.map(child => {
if (child.title === "Item" || child.title === "Group") {
const data = {
id: child.id,
name: child.subtitle,
type: child.type,
children: getChildren(child.children),
child_id: child.children
? child.children.map(child => child.id)
: []
};
if (data.children.length === 0) delete data.children;
if (data.child_id.length === 0) delete data.child_id;
return data;
} else {
return {
id: child.id,
name: child.subtitle,
type: child.type
};
}
})
: [];
}
const data = {
id: id,
name: subtitle,
type: type,
children: getChildren(children),
child_id: children ? children.map(child => child.id) : []
};
if (data.children.length === 0) delete data.children;
if (data.child_id.length === 0) delete data.child_id;
return data;
});
The HTML part that calls the stringify method
<div className="json">
<p> {JSON.stringify(mappedData)}</p>
</div>
I found a Replacer that it works but the JSON result is too long for what I need
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
JSON.stringify(circularReference, getCircularReplacer());
And here's the result :
[{"id":"7a69fc68","name":{"type":"input","key":null,"ref":null,"props":{"className":"inputSubs","type":"text","placeholder":"Category Name"},"_owner":{"tag":1,"key":null,"stateNode":{"props":{},"context":{},"refs":{},"updater":{},"notificationAlert":{"current":{"props":{},"refs":{"notifications":{"__reactInternalInstance$6qqi1p3qi9b":{"tag":5,"key":null,"elementType":"div","type":"div","return":{"tag":1,"key":null,"return":{"tag":5,"key":null,"elementType":"div","type" .. etc
Any Help ?
Related
I have a JSON file and I am trying to calculate the JSON file key based on the value and reformating it. My JSON file looks like below:
data=[
{
pet:'Cat',
fruit:'Apple',
fish:'Hilsha'
},
{
pet:'Dog',
fish:'Carp'
},
{
pet:'Cat',
fruit:'Orange',
fish:'Lobster'
}
];
I do like to calculate and formate it like below:
data=[
{
label:'Pet',
total:3,
list:[
{
name:'Cat',
value: 2,
},
{
name:'Dog',
value: 1,
}
]
},
{
label:'Fruit',
total:2,
list:[
{
name:'Apple',
value: 1,
},
{
name:'Orange',
value: 1,
}
]
},
{
label:'Fish',
total:3,
list:[
{
name:'Hilsha',
value: 1,
},
{
name:'Carp',
value: 1,
},
{
name:'Lobster',
value: 1,
}
]
},
];
If anybody can help me, it will be very help for me and will save a day.
I have fixed this task myself. If I have any wrong, you can put your comment fill-free :)
``
ngOnInit(): void {
this.dataService.$data.subscribe(data => {
// Create new object and calculation according to category
let petObj: any = {}
let fruitObj: any = {}
let fishObj: any = {}
data.forEach((el: any) => {
if (el.pet != undefined) {
petObj[el.pet] = (petObj[el.pet] || 0) + 1;
}
if (el.fruit != undefined) {
fruitObj[el.fruit] = (fruitObj[el.fruit] || 0) + 1;
}
if (el.fish != undefined) {
fishObj[el.fish] = (fishObj[el.fish] || 0) + 1;
}
});
// Create list according to category
let pet_list: any = [];
let fruit_list: any = [];
let fish_list: any = [];
for (var key in petObj) {
let pet = {
label: key,
value: petObj[key]
}
pet_list.push(pet)
}
for (var key in fruitObj) {
let fruit = {
label: key,
value: fruitObj[key]
}
fruit_list.push(fruit)
}
for (var key in fishObj) {
let fish = {
label: key,
value: fishObj[key]
}
fish_list.push(fish)
}
// Calculate total sum according to category
var totalPet = pet_list.map((res: any) => res.value).reduce((a: any, b: any) => a + b);
var totalFruit = fruit_list.map((res: any) => res.value).reduce((a: any, b: any) => a + b);
var totalFish = fish_list.map((res: any) => res.value).reduce((a: any, b: any) => a + b);
// Rearrange the JSON
this.rearrangeData = [
{
label: 'Pet',
total: totalPet,
list: pet_list
},
{
label: 'Fruit',
total: totalFruit,
list: fruit_list
},
{
label: 'Fish',
total: totalFish,
list: fish_list
}
]
console.log(this.rearrangeData)
// End rearrange the JSON
});
}
``
You can simplify your function. Take a look this one
group(oldData) {
const data = []; //declare an empty array
oldData.forEach((x) => {
//x will be {pet: 'Cat',fruit: 'Apple',fish: 'Hilsha'},
// {pet: 'Dog',fish: 'Carp'}
// ...
Object.keys(x).forEach((key) => {
//key will be 'pet','fruit',...
const item = data.find((d) => d.label == key); //search in the "data array"
if (item) { //if find it
item.total++; //add 1 to the property total of the element find it
// and search in the item.list the 'Cat'
const list = item.list.find((l) => l.name == x[key]);
//if find it add 1 to the property value of the list
if (list)
list.value++;
else
//if not, add to the list
//an object with property "name" and "value" equal 1
item.list.push({ name: x[key], value: 1 });
} else
//if the element is not in the "array data"
//add an object with properties label, total and list
//see that list is an array with an unique element
data.push({
label: key,
total: 1,
list: [{ name: x[key], value: 1 }],
});
});
});
return data;
}
You can use like
this.dataService.$data.subscribe(data => {
this.rearrangeData=this.group(data)
}
NOTE: this function the labels are 'pet','fruit' and 'fish' not 'Pet', 'Fruit' and 'Fish'
Did you try reading the text leading up to this exercise? That'd be my first approach. After that, I'd use reduce. You can do pretty much anything with reduce.
I would like to get filterd the particular array alone from the json response when dataID is not matched with the ParentDataID from another array in same json response using typescript feature in Angular 7
{ "data":[
{
"dataId":"Atlanta",
"parentDataId":"America"
},
{
"dataId":"Newyork",
"parentDataId":"America"
},
{
"dataId":"Georgia",
"parentDataId":"Atlanta"
},
{
"dataId":"South",
"parentDataId":"Atlanta"
},
{
"dataId":"North",
"parentDataId":"South"
}
]
}
In above response the value of dataId Newyork is not matched with any of the parentDataId entire array json response. So Now i want to filtered out only the second array of DataID alone to make new array.
I would like to have this validation in Typescript angular 7
My output is supposed to like below... The DataId does not have the parentDataId
[
{
"dataId":"Newyork",
"parentDataId":"America"
},
{
"dataId":"Georgia",
"parentDataId":"Atlanta"
},
{
"dataId":"North",
"parentDataId":"South"
}
]
Appreciate the help and response
You can use filter method:
let filterKey = 'Atlanta';
const result = data.data.filter(f=> f.parentDataId != filterKey
&& f.dataId != filterKey);
An example:
let data = { "data":[
{
"dataId":"Atlanta",
"parentDataId":"America"
},
{
"dataId":"Newyork",
"parentDataId":"America"
},
{
"dataId":"Georgia",
"parentDataId":"Atlanta"
}
]
};
let filterKey = 'Atlanta';
const result = data.data.filter(f=> f.parentDataId != filterKey
&& f.dataId != filterKey);
console.log(result);
demo in this StackBlitz Link
my solution is like below code snippet. ts
reducedData = [...this.data];
this.data.reduce((c,n,i) => {
this.data.reduce((d,o, inex) => {
if ( n.dataId === o.parentDataId){
this.reducedData.splice(i,1, {'dataId': 'removed', parentDataId: 'true'});
} else {
return o;
}
},{});
return n;
}, {});
this.reducedData = this.reducedData.filter (value => value.dataId !== 'removed');
html file
<h4> dataId does not have parentId </h4>
<hr>
<pre>
{{reducedData | json}}
</pre>
EDIT
If you do not want to use second object reducedData, then below solution is fine to work.. StackBlitz Link
component.ts
this.data.reduce((c,n,i) => {
this.data.reduce((d,o, inex) => {
if ( n.dataId === o.parentDataId) {
this.data[i]['removed'] = "removed";
} else{
return o;
}
},{});
return n;
}, {});
this.data = this.data.filter (value => value['removed'] !== 'removed');
component.html
<h4> dataId does not have parentId </h4>
<hr>
<pre>
{{data |json}}
</pre>
Please try like this.
const data = { "data":[
{
"dataId":"Atlanta",
"parentDataId":"America"
},
{
"dataId":"Newyork",
"parentDataId":"America"
},
{
"dataId":"Georgia",
"parentDataId":"Atlanta"
}
]
};
const filterKey = "Newyork"
const matchExist = data.data.some( item => item.parentDataId === filterKey && item.dataId === filterKey)
let filteredArray ;
if(!matchExist){
filteredArray = data.data.find(item => item.dataId === filterKey )
}
I want to display display list of districts from the json, receiving the following error
'TypeError: suggestion.districts.slice(...).toLowerCase is not a function'
json file.
How can I get the list of districts details, so that I can perform autocomplete using downshift?
any help appreciated.
json format
{
"states":[
{
"state":"Andhra Pradesh",
"districts":[
"Anantapur",
"Chittoor",
"East Godavari",
]
},
{
"state":"Arunachal Pradesh",
"districts":[
"Tawang",
"West Kameng",
"East Kameng",
]
},
}
component
import React, { Component } from 'react'
import statedist from "./StateDistrict.json";
const suggestions = statedist.states;
/*.... */
function getSuggestions(value, { showEmpty = false } = {}) {
// const StatesSelected=props.StatesSelected;
const inputValue = deburr(value.trim()).toLowerCase();
const inputLength = inputValue.length;
let count = 0;
//console.log(StatesSelected)
return inputLength === 0 && !showEmpty
? []
: suggestions.filter(suggestion => {
const keep =
count < 5 &&
suggestion.districts.slice(0, inputLength).toLowerCase() === inputValue;
if (keep) {
count += 1;
}
return keep;
});
}
function renderSuggestion(suggestionProps) {
const {
suggestion,
index,
itemProps,
highlightedIndex,
selectedItem
} = suggestionProps;
const isHighlighted = highlightedIndex === index;
const isSelected = (selectedItem || "").indexOf(suggestion.districts) > -1;
return (
<MenuItem
{...itemProps}
key={suggestion.districts[0]}
selected={isHighlighted}
component="div"
style={{
fontWeight: isSelected ? 500 : 400
}}
>
{suggestion.districts[0]} -- how can I get all the values instead of one here
</MenuItem>
);
}
class autoCompleteState extends Component {
constructor(props) {
super(props);
this.state = {
SelectedState:'',
}
// this.showProfile = this.showProfile.bind(this)
}
setSelectedDistrict = (newState) => {
this.setState({ SelectedState: newState });
console.log(newState)
this.props.onDistrictSelected(newState);
}
render() {
const { classes, } = this.props;
console.log(this.state.SelectedState)
const StatesSelected=this.props.StateList;
return (
<div>
<DownshiftMultiple
classes={classes}
setSelectedDistrict={this.setSelectedDistrict}
StatesSelected={StatesSelected}
/>
</div>
)
}
}
export default withStyles(Styles)(autoCompleteState);
I want the district details to come as suggestion like state in the below image
Currently, you are doing this:
suggestion.districts.slice(0, inputLength).toLowerCase() === inputValue;
This is throwing an error because .slice is copying inputLength items from your districts array and then trying to call .toLowerCase() on that array.
If I understand correctly, you are trying to filter your districts according to the inputValue. One way of doing this would be to use reduce on the districts array like this:
suggestion.districts.reduce((acc,curr)=>curr.substring(0,inputLength)===inputValue?[...acc,curr.substring(0,inputLength)]:acc, [])
If you only want the first 5 then you can slice the result of this:
suggestion.districts.reduce((acc,curr,index)=>index<5&&curr.substring(0,inputLength)===inputValue?[...acc,curr.substring(0,inputLength)]:acc, [])
As I asked yesterday in my first post, I have a json file that looks like this:
groups:{[
{
title:Animal
shown:false
data:[{....}]
}
........
.....
]}
I want to change the shown value on a button click. The closest thing I found to my problem was this part of code:
newState = this.state.groups.map((val,i) => {
if(index === i){
return { ...val, shown: false};
}
return val;
})
this.setState({
groups: newState,
})
However, it doesn't seem to work, logging on console doesn't show any differences before and after the button press. I'm rather new to this so do you mind to help me understand what i did bad?
edit: I tried changing from index to a simple number to see if that was the problem, but still the same problem.
A JSON object is collection of Key Value pairs. i.e.
let FullName = {
firstName: "Stack",
lastName: "OverFlow"
}
In FullName Object Keys are firstName and lastName and corresponding values are "Stack" and "Overflow".
The groups Object that you have defined is missing the key Property.
Coming to Your problem:
Case1: If groups Object is an Array of Objects then:
var groups = [
{
title: 'Animal',
shown: false,
data: [{}]
},
{
title: 'Birds',
shown: false,
data: [{}]
}
]
/* Upadate By Index value */
/*
var index = 1;
let updatedGroup = groups.map((val,i) => {
if(index === i){
return { ...val, shown: true};
}
return val;
})
*/
/* Upadate By title */
/* let title = "Animal";
let updatedGroup = groups.map((val,i) => {
if(val.title === title){
return { ...val, shown: true};
}
return val;
}) */
// To toggle the shown Value Each Time
let title = "Animal";
let updatedGroup = groups.map((val,i) => {
if(val.title === title){
return { ...val, shown: !val.shown};
}
return val;
})
console.log("updatedGroup", updatedGroup);
Case2: If groups Object is Object of Objects then
var groups = {
group1: {
title: 'Animal',
shown: false,
data: [{}]
},
group2: {
title: 'Birds',
shown: false,
data: [{}]
}
}
let index = 1;
let updatedGroup = Object.values(groups).map((val, i)=>{
if(index === i){
return { ...val, shown: true};
}
return val;
})
console.log("updatedGroup",updatedGroup)
I have an obj like this:
var obj = { thing1 : { name: 'test', value: 'testvalue1'},
thing2 : { name: 'something', thing4: {name:'test', value: 'testvalue2'}},
}
I want to write a function like findByName(obj, 'test').It returns all the matching sub-objects with the same name. So it should return:
{ name: 'test', value: 'testvalue1'}
{name:'test', value: 'testvalue2'}
Right now this is what i have:
function findByName(obj, name) {
if( obj.name === name ){
return obj;
}
var result, p;
for (p in obj) {
if( obj.hasOwnProperty(p) && typeof obj[p] === 'object' ) {
result = findByName(obj[p], name);
if(result){
return result;
}
}
}
return result;
}
obviously it only return the first matching.. how to improve this method?
You need to push the results into an array and make the function return an array.
Also, do a sanity check whether the object is null or undefined to avoid errors.
Here is your code modified.
Note: I have also modified the parent object ,which is "obj", by adding a "name" property with value "test" so the result should have the parent object in the result as well.
function findByName(obj, name) {
var result=[], p;
if(obj == null || obj == undefined)
return result;
if( obj.name === name ){
result.push(obj);
}
for (p in obj) {
if( obj.hasOwnProperty(p) && typeof obj[p] === 'object') {
newresult = findByName(obj[p], name);
if(newresult.length>0){
//concatenate the result with previous results found;
result=result.concat(newresult);
}
}
}
return result;
}
var obj = { thing1 : { name: 'test', value: 'testvalue1'},
thing2 : { name: 'something', thing4: {name:'test', value: 'testvalue2'}},
name:'test' //new property added
}
//execute
findByName(obj,"test");
Run this in your console and upvote if this helps you.