I'm having some issue on rendering some JSON data into a React Table (which comes from the library react-table). Here is an exemple of a json I'm working with :
const translateditems = [
{
id: 1,
colonne1: [
{
language: 'en',
content: 'Column n°1'
},
{
language: 'fr',
content: 'Colonne n°1'
}
],
colonne2: [
{
language: 'en',
content: 'Column n°2'
},
{
language: 'fr',
content: 'Colonne n°2'
}
],
dateCreated: '2018 - 02 - 01 30: 00: 00.000'
}
]
For a chosen language, I need to only show one object of the translated texts of each column if needed. (In this example, the date does not need to be translated in any particular language)
Here is how I render my react-table :
constructor () {
super()
this.state = {
data: translateditems
}
}
render () {
const { data } = this.state
const headers = []
// I use all the name fields in the first json object as headers
for (var key in Object.keys(data[0])) {
headers.push(Object({
'content': Object.keys(data[0])[key]
}))
}
return (
<div>
<ReactTable
data={data}
columns={headers.map(header => {
return ({
Header: header.content,
accessor: header.content
})
})
}
defaultPageSize={10}
className='-striped -highlight'
/>
<br />
</div>
)
}
Do you have any clue on how to do this ?
UPDATE
Here's what I did to solve my problem :
return (
<div>
<ReactTable
data={data}
columns={headers.map(header => {
return ({
Header: header.content,
accessor: header.content,
// I added a function to apply on my Cell
Cell: row => (
<div>{this.renderTranslatedItem(data, header.content, row.index)}</div>
)
})
})
}
defaultPageSize={10}
className='-striped -highlight'
/>
<br />
</div>
)
And here's the function I made (assuming lang to be the language I want):
renderTranslatedItem (data, column, rowIndex) {
// I check if the value is an array -> if it's not, then I return null
if (Object.prototype.toString.call(data[rowIndex][column]) !== '[object Array]') {
return null;
}
for (var i in data[rowIndex][column]) {
if (data[rowIndex][column][i].language === lang) {
return data[rowIndex][column][i].content
}
}
}
for (var key in Object.keys(data[0])) {
const headers = []
// I use all the name fields in the first json object as headers
headers.push(Object({
'content': Object.keys(data[0])[key]
}))
}
In my example, I consider lang is passed through your props.
You have to replace it by:
const { lang } = this.props
const headers = Object.keys(data[0]).reduce(
(acc, key)=> {
return key!=='id' && key!=='dateCreated' && data[0][key][lang]
? { ...acc, [key] : data[0][key][lang] }
: { ...acc, [key]:null }
},{})
//console.log(headers) will output this:
{
colonne1:'colonne1',
colonne2:'colonne2'
}
Related
I'm working with some script and I would like to ask how to display on the console a specific json value.
For example, I have script:
Promise.all([
fetch('https://blockchain.info/balance?active=3C6WPNa5zNQjYi2RfRmt9WUVux7V4xbDmo').then(resp => resp.json()),
fetch('https://api.binance.com/api/v3/avgPrice?symbol=BTCEUR').then(resp => resp.json()),
]).then(console.log)
output:
[{
3C6WPNa5zNQjYi2RfRmt9WUVux7V4xbDmo: {
final_balance: 185653,
n_tx: 1,
total_received: 185653
}
}, {
mins: 5,
price: "19230.49330261"
}]
I want to console price and final_balance.
Best regards!
One way you could achieve this is by flattening the array and objects within because there's no predefined structure of what the output looks like.
Here, I'm assuming the output you mentioned is always an array of objects.
const flattenObject = (obj = {}) =>
Object.keys(obj || {}).reduce((acc, cur) => {
if (typeof obj[cur] === "object") {
acc = { ...acc, ...flattenObject(obj[cur]) };
} else {
acc[cur] = obj[cur];
}
return acc;
}, {});
const outputs = [
{
"3C6WPNa5zNQjYi2RfRmt9WUVux7V4xbDmo": {
final_balance: 185653,
n_tx: 1,
total_received: 185653,
},
},
{
mins: 5,
price: "19230.49330261",
},
];
outputs.forEach((output) => {
const flatOutput = flattenObject(output);
console.log("flatOutput:", flatOutput);
if (flatOutput.final_balance) {
console.log("final_balance:", flatOutput.final_balance);
}
if (flatOutput.price) {
console.log("price:", flatOutput.price);
}
});
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 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 ?
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, [])
I am developing an application with React and I have a problem. I have made a fetch from a json and the values are repeated. I want only each value to appear once.
I hope that it only returns once each of the elements of "Padre": "CRM", "Permisos" and "Telefonia". The same for "Hijo".
I've tried changing ".concat" to ".reduce" because I've read that it can be done like this, but it does not work. I have seen examples but none of them works on "this.state" so I do not know how to do it.
Can you help me with the correct way to do it?
This is a part of my json file
[
{
"Id":"114",
"Padre":"CRM",
"Hijo":"Argumentarios"
},
{
"Id":"115",
"Padre":"CRM",
"Hijo":"Argumentarios"
},
{
"Id":"116",
"Padre":"CRM",
"Hijo":"Argumentarios"
},
{
"Id":"44",
"Padre":"Permisos",
"Hijo":"root"
},
{
"Id":"45",
"Padre":"Permisos",
"Hijo":"root"
},
{
"Id":"46",
"Padre":"Permisos",
"Hijo":"root"
},
{
"Id":"47",
"Padre":"Permisos",
"Hijo":"root"
},
{
"Id":"50",
"Padre":"Telefonia",
"Hijo":"Audio"
},
{
"Id":"51",
"Padre":"Telefonia",
"Hijo":"Audio"
},
{
"Id":"52",
"Padre":"Telefonia",
"Hijo":"Configuracion"
},
{
"Id":"70",
"Padre":"Telefonia",
"Hijo":"Rutas"
}
]
For confidential reasons I can not show the actual file.
In my next code I change the fetch for a fake json url
I Edit my code with #Avanthika and #blaz code. Currently the code works but shows only the first value it finds of "Father" and "Son". I need to show only once each of the different values of "Father" and "Son". Example result:
Father:
CRM
PERMISOS
Son:
ARGUMENTARIOS
ROOT
Currenly, with my new code i see only: CRM (Padre) and Argumentarios (Son). The rest of the elements are not shown.
import React, { Component } from 'react';
class Nav extends Component{
constructor(props){
super(props)
this.state = {
menuSubmenu:[]
}
}
componentWillMount(){
fetch('http://FAKE.php')
.then(response => response.json())
.then(menuSubmenu =>{
menuSubmenu.forEach(datos => {
let data = {
menu:datos.Padre,
submenu:datos.Hijo,
id:datos.Id
}
//console.log( data )
//console.log (data.menu);
this.setState({
menuSubmenu:this.state.menuSubmenu.concat([data])
})
})
})
}
render() {
const array = [...this.state.menuSubmenu];
const distinctValues = array.filter(
({ Padre, Hijo }, index) => {
return array.findIndex(item => item.Padre === Padre && item.Hijo === Hijo) === index;
});
//console.log(this.state.menuSubmenu);
//console.log(distinctValues);
if (distinctValues.length > 0) {
return(
<div>
{distinctValues.map(datos => <Navegacion key={datos.id} menu={datos.menu} submenu={datos.submenu} />)}
</div>
);
}
return (<p>Cargando usuarios...</p>);
}
}
class Navegacion extends Component{
render(){
return (
<ul className="list">
<li className="list__item">{this.props.menu}
<ul className="list">
<li className="list__item">
{this.props.submenu}
</li>
</ul>
</li>
</ul>
)
}
}
export default Nav;
This image is the result of my json.My json result
I hope you can help me with the "reduce" function.
¡Thanks a lot!
Hi you can use lodash and function uniqBy https://lodash.com/docs#uniqBy
_.uniqBy(menuSubmenu, function (e) {
return e.Padre;
});
You can use new Set to unique your array list by Padre and Hijo.
const array = [{"Id":"114","Padre":"CRM","Hijo":"Argumentarios"},
{"Id":"115","Padre":"CRM","Hijo":"Argumentarios"},
{"Id":"116","Padre":"CRM","Hijo":"Argumentarios"},
{"Id":"44","Padre":"Permisos","Hijo":"root"},
{"Id":"45","Padre":"Permisos","Hijo":"root"},
{"Id":"46","Padre":"Permisos","Hijo":"root"},
{"Id":"47","Padre":"Permisos","Hijo":"root"},
{"Id":"50","Padre":"Telefonia","Hijo":"Audio"},
{"Id":"51","Padre":"Telefonia","Hijo":"Audio"},
{"Id":"52","Padre":"Telefonia","Hijo":"Configuracion"},
{"Id":"70","Padre":"Telefonia","Hijo":"Rutas"}];
const distinctValues = Array.from(new Set(array.map(elem => `${elem.Padre}-${elem.Hijo}`))).map(distinctVal => {
const [ Padre, Hijo ] = distinctVal.split("-");
return ({
Id: array.find(elem => elem.Padre === Padre && elem.Hijo === Hijo).Id,
Padre,
Hijo
});
});
console.log(distinctValues);
Or you can go for lodash as mentioned to extract uniq values. You have to use uniqBy.
const array = [{"Id":"114","Padre":"CRM","Hijo":"Argumentarios"},
{"Id":"115","Padre":"CRM","Hijo":"Argumentarios"},
{"Id":"116","Padre":"CRM","Hijo":"Argumentarios"},
{"Id":"44","Padre":"Permisos","Hijo":"root"},
{"Id":"45","Padre":"Permisos","Hijo":"root"},
{"Id":"46","Padre":"Permisos","Hijo":"root"},
{"Id":"47","Padre":"Permisos","Hijo":"root"},
{"Id":"50","Padre":"Telefonia","Hijo":"Audio"},
{"Id":"51","Padre":"Telefonia","Hijo":"Audio"},
{"Id":"52","Padre":"Telefonia","Hijo":"Configuracion"},
{"Id":"70","Padre":"Telefonia","Hijo":"Rutas"}];
const distintValues = _.uniqBy(array, elem => [elem.Padre, elem.Padre].join());
console.log(distintValues);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
You need to fix the solution this way:
render() {
const array = [...this.state.menuSubmenu];
// Put the solution you like here.
// const distinctValues = the solution you like
if (distinctValues.length > 0) {
return(
<div>
{distinctValues.map(datos => <Navegacion key={datos.id} menu={datos.menu} submenu={datos.submenu} />)}
</div>
);
}
return (<p>Cargando usuarios...</p>);
}
Original solution from Avanthika doesn't work because in your data, some item might possibly have Padre value containing dash character ("-"). Use a character that will never appear in Padre value as separator instead and you will be good.
My solution:
Use Array.prototype.filter
const distinctValues = this.state.menuSubmenu.filter(
({ Padre, Hijo }, index) => {
return this.state.menuSubmenu.findIndex(item => item.Padre === Padre && item.Hijo === Hijo) === index;
});
With Array.prototype.reduce it will look more bulky:
const distinctValues = this.state.menuSubmenu.reduce(
(array, item) => {
if (array.findIndex(i => i.Padre === item.Padre && i.Hijo === item.Hijo) === -1) {
array.push(item);
}
}, []);