I'm new to RN and am trying to show a ListView populated with data from a json array, If I use a simple array then I can see the data however when I use the json array as shown in the code I don't see anything populated when I run the emulator. Is there a specific way to handle the json in my example below to show it in the ListView:
class FetchExample extends Component {
constructor(props) {
super(props);
// Initialize the hardcoded test data - to be replaced by JOSN fetch
let data = {"Vehicles":[[
{"vehicle_make": "Toyota",
"vehicle_model": "Camry",
"vehicle_year": "2015",
"vehicle_price_range": "$$ (10-30)",
"car_id": 1127,
"vehicle_color": "Black",
"vehicle_car_accidents": "No",
"vehicle_no_owners": "1",
"car_vehicle_location": "Lot",
"vehicle_city_location": "L.A",
"vehicle_mileage": 10864,
"vehicle_vin": 1234,
"vehicle_off_lease": "Yes",
"vehicle_state": "CA"
}]]};
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(data)
};
console.log(data);
}
render() {
return (
<View style={{paddingTop: 22}}>
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => <Text>{rowData.Vehicles}</Text>}
/>
</View>
);
}
}
If I refer to the docs, It looks like your data should be an array rather than an object. can you try with the following?
let data = [
{"vehicle_make": "Toyota",
"vehicle_model": "Camry",
"vehicle_year": "2015",
"vehicle_price_range": "$$ (10-30)",
"car_id": 1127,
"vehicle_color": "Black",
"vehicle_car_accidents": "No",
"vehicle_no_owners": "1",
"car_vehicle_location": "Lot",
"vehicle_city_location": "L.A",
"vehicle_mileage": 10864,
"vehicle_vin": 1234,
"vehicle_off_lease": "Yes",
"vehicle_state": "CA"
}];
edit:
you can instead replace
dataSource: ds.cloneWithRows(data)
with
dataSource: ds.cloneWithRows(data.Vehicles[0])
but I'd suggest you flatten your data as much as you can.
edit 2:
The render method also needs modification. try to change renderRow to the following:
renderRow={(rowData) => <Text>{rowData.vehicle_make}</Text>}
Related
I have a React form that uses i18 next translations from JSON file in a dropdown. The objects are very simple: one key, one translation, like this (but the file is very long, there are dozens of keys).
JSON:
{
"country": "Country",
"big": "Big",
"dog": "Dog",
"integration": "Integration"
}
Code that uses data from JSON:
const createField = (parentName: string, item: any) => {
const field = {
type: `${item.type}`,
name: `${parentName ?? ''}${parentName?.length ? '.' : ''}${item.name}`,
label: t(`${item.label ?? item.name}`),
properties: {
placeholder: `${item.placeholder ?? ''}`
} as any,
};
if (item.type === 'select' ) {
field.properties = {
...field.properties,
options: [].concat(item.options?).sort((a,b) =>
t(`${a.value}`) > t(`${b.value}`) ? 1 : -1).map((option: any) => {
return {
label: t(`${option.label}`),
value: option.value
};
}),
};
};
};
I want the dropdown to be sorted according to the value alphabetically because in each language the order would be different. Everything I tried sorts the array from this JSON according to the key.
I tried concat(item.options?) for sorting but getting errors "Expression expected" and "property doesn't exist".
Also tried this solution, but the dropdowns turned from text into random numbers.
if (item.type === 'select' ) {
field.properties = {
...field.properties,
options: Object.entries(item.options)
.sort(([key1], [key2]) => t(key1).localeCompare(t(key2)))
.map(([label, value]) => ({
label: t(label),
value
}))
};
};
Issue
Assuming that item.options is the JSON data you are trying to sort and convert to a list of options, then the issue is that you've appended the entire options object instead of each individual option. The result is an array of length 1. Another issue is that your data is a dictionary of key-value pairs, not an array of objects with label and value properties.
Solution
You can use both Object.entries and Object.fromEntries to convert the object to an array of key-value pairs and back. For the sorting function you want to sort by the key, and since the keys are strings, use localeCompare for the string comparison.
const data = {
country: "Country",
big: "Big",
dog: "Dog",
integration: "Integration"
};
const sortedData = Object.fromEntries(
Object.entries(data).sort(([key1], [key2]) => key1.localeCompare(key2))
);
console.log(sortedData);
Since you really want an array of shape [{ label: '...', value: '...' }, ...] you can use an array.map to map the array of key-value pairs to an array of objects with the shape you need for mapping in the option values.
const data = {
country: "Country",
big: "Big",
dog: "Dog",
integration: "Integration"
};
const sortedData = Object.entries(data)
.sort(([key1], [key2]) => key1.localeCompare(key2))
.map(([label, value]) => ({
label,
value
}));
console.log(sortedData);
For the actual rendering of your options:
options: Object.entries(item.options)
.sort(([key1], [key2]) => t(key1).localeCompare(t(key2)))
.map(([label, value]) => ({
label: t(label),
value
}))
Since it's not very clear which of the key or value of the JSON data is your option label/value you may needs to tweak the above to fit. I can help here if needed.
Hope it helps:
sort object by key and result is an array of sorted keys
const obj={
"country": "Country",
"big": "Big",
"dog": "Dog",
"integration": "Integration"
}
const sortedKeys=Object.keys(obj).sort();
console.log(sortedKeys);
sort object by value and result is an array of sorted values
const obj={
"country": "Country",
"big": "Big",
"dog": "Dog",
"integration": "Integration"
}
const sortedValues=Object.values(obj).sort();
console.log(sortedValues)
sort object by value and result is an object
const obj={
"country": "Country",
"big": "Big",
"dog": "aDog",
"integration": "Integration"
}
//for case insensitive use this function
const sortedByValue=Object.values(obj).sort(function(a, b) {
return (a.toUpperCase() < b.toUpperCase()) ? -1 : (a.toUpperCase() > b.toUpperCase()) ? 1 : 0;
})
function getKeyByValue(value) {
return Object.keys(obj).find(key => obj[key] === value);
}
const sortedObj={};
sortedByValue.map(value=>{
const key=getKeyByValue(value)
sortedObj[key]=value;
})
console.log(sortedObj)
I made and API call using fetch to get JSON data. That data is then passed to my function displayCartTotal, which accepts a parameter that uses de-structuring to obtain results.
In displayCartTotal, I want to de-structure the first item into the results array, into a data variable. Next, use object de-structuring to obtain the itemsInCart and buyerCountry properties of the data.
I have tried de-structuring the array, but is not working, also when i do typeof() on the data I receive, I get "object".
Here is format of the JSON data
{
results: [{
itemsInCart: [{
name: "Jolof Rice",
price: 80,
qty: 2
}, {
name: "Jolof Rice",
price: 80,
qty: 2
}],
buyerCountry: "Uganda"
}],
info: {
seed: "85e0e8ca0e095f74",
results: "1",
page: "1",
version: "0.1",
time: {
instruct: 11,
generate: 5
}
}
}
Code:
const displayCartTotal = ({results}) => {
const [data] = results;
const [itemsInCart,buyerCountry] = data;
return results;
};
const fetchBill = () => {
const api = 'https://randomapi.com/api/006b08a801d82d0c9824dcfdfdfa3b3c';
fetch(api)
.then(response => response.json())
.then(data => displayCartTotal(data))
.catch(error => console.error(error));
};
I expect to de-structure the first item in the results array into a data variable. And also to use object de-structuring to obtain the itemsInCart and buyerCountry properties of data.
Have you tried placing the nth position of the object
const displayCartTotal= ({results})=>{
const {0: data} = results;
const {itemsInCart, buyerCountry} = data;
}
i'm new to coding and i'm building a web app using reactjs. i need to render a widget that contains a table to display data that comes from the back-end in json format. The table will change dynamically over time and will always be different.
I found a library that could work for me :
https://github.com/thehyve/react-json-to-table
It works like wonders, but i can't render clickable urls in the tables.
Someone can help me archieve this?
i have some data like this:
{
"Loaded by": "Jills",
"Load id": 34,
"git id": "xxqaygqertqsg98qhpughqer",
"Analysis Id": "7asdlnagsd98gfaqsgf",
"Load Date": "July 12, 2018",
"Data Source": "Study XY123-456",
"Jira Ticket": "Foo-1",
"Confluence URL": "http://myserver/wxyz"
}
the my component looks like this:
export default class TableWidget extends BaseWidget {
constructor(props) {
super(props);
const { data } = this.props;
const data2 = data;
this.state = {
data: this.getData(data2)
};
this.handleResize = this.handleResize.bind(this);
}
componentWillMount() {
super.componentWillMount();
this.props.socket.on(`widget:update:${this.props.jobName}:${this.props.name}`, datas => {
logger('info', `updating widget: ${this.props.jobName}:${this.props.name}`, datas);
this.setState({
data: this.getData(datas.value),
});
});
}
getData(data) {
const demoJson = {
"Loaded by": "Jills",
"Load id": 34,
"git id": "xxqaygqertqsg98qhpughqer",
"Analysis Id": "7asdlnagsd98gfaqsgf",
"Load Date": "July 12, 2018",
"Data Source": "Study XY123-456",
"Jira Ticket": "Foo-1",
"Confluence URL": "http://myserver/wxyz"
};
if (data == null )
return demoJson;
else
return data;
}
static get layout() {
return {
x: 0,
y: 0,
w: 4,
h: 3,
minH: 3,
maxH: 40,
minW: 4,
maxW: 10,
};
}
static get className() {
return 'TableWidget';
}
handleResize() {
this.chart.reflow();
}
render() {
const classList = classNames(...this.classList, 'widget', 'widget__table',);
return (
<div className={classList}>
<h1 className="widget__title">{this.props.title}</h1>
<JsonToTable json={this.state.data} />
</div>
);
}
}
TableWidget.propTypes = {
title: PropTypes.string.isRequired,
};
the table renders fine but i want to be albe to clikc on the "conference url". how can i archieve this?
maybe I could use one of these two libraries?
https://github.com/arqex/react-json-table
or
https://github.com/agracio/ts-react-json-table
thanks for the help and sorry if i made some English or code abominations.
I have a JSON file with nested arrays of varying length. That is, each object has an ARR with a different number of objects.
{ "count": 200,
"objects": [
{
"id": "FIRST",
"b": "two",
"c": "three",
"ARR": [{
"aa": "onion ",
"bb": 2,
"cc": "peanuts"},
},
{
"aa": "Jam ",
"bb": 4,
"cc": "Bread"},
}],
"d":"four"
]
}, . . . on and on
I have imported the JSON data to my JavaScript file:
const data = JSON.parse(require('fs').readFileSync('./jsonfiles/objects.JSON', 'utf8'))
trim data down to the objects of interest
const objs=data.objects;
I'm using Sequelize to write this to a mysql database. I have two models: Model 1: hasMany Arr sets: Model 2: belongsTo Model1.
Writing the to table1 from Model1 works well like this:
for (var key in Objs) {
var item = Objs[key]
db.Model1.create({
modelID: item.id,
modelB: item.b,
modelC:item.c
})
}
Now, I'm trying to write ARR to the associated model and am stumped on how to do this.
I do not know how many objects will be in each ARR
Storing ARR as a JSON obj in table1 won't serve well later.
This is the function I created for our companies API. Took me a week to put together but hopefully, this helps.
exports.functionName = async (req, res) => {
const params = req.params.something;
if (!params) {
res.status(httpStatusCodes.BAD_REQUEST).send({message:'Please provide params'});
return;
}
const function = inputs.map(prop => ({
propOne: uniqueID,
propTwo: prop.value,
}));
const value = await productInput.bulkCreate(function);
if (!value || value.length < 1) {
res.status(httpStatusCodes.INTERNAL_SERVER_ERROR).send({ message:'No inputs were updated for this product.' });
return;
}
res.send(value);
return;
};
My react-redux app is getting a single record in JSON but the record is an array and therefore it looks like this (notice [ ] brackets):
{"person":[{"PersonID":1,"Name":"John Smith","Gender":0}]}
So, the redux store shows it as person->0->{"PersonID":1,"Name":"John Smith","Gender":0}. As such, the state shows that the person object is empty:
Name: this.props.person?this.props.person.Name:'object is empty',
My PersonPage.js includes the details page like this:
<PersonDetail person={this.props.person} />
The details page has this:
import React from 'react';
import classnames from 'classnames';
class PersonDetail extends React.Component {
state = {
Name: this.props.person?this.props.person.Name:'',
PersonID: this.props.person?this.props.person.PersonID:null,
loading: false,
done: false
}
componentWillReceiveProps = (nextProps) => {
this.setState({
PersonID: nextProps.person.PersonID,
Name: nextProps.person.Name
});
}
This is my raw Redux state:
people: [
[
{
PersonID: 51,
Name: 'John Smith',
Gender: 0
}
]
]
Person is an array, that contains the object in which Name key is present, so you need to use index also, write it like this:
this.props.person && this.props.person.length ? this.props.person[0].Name : '';
Check this example:
var data = {
"person":[
{
"PersonID":1,
"Name":"John Smith",
"Gender":0
}
]
};
console.log('Name: ', data.person[0].Name);
I think that you are supposed to map the person detail foreach person's data.
on the PersonPage.js ,
map it as follows:
{
this.props.person.map((p)=>{
return (<PersonDetail person={p} />)
})
}
If I was you I would make an util function like this:
const parsePeople = people => {
if (people instanceof Array) return parsePeople(people.pop())
return people
}
const people = [
[{
PersonID: 51,
Name: 'John Smith',
Gender: 0
}]
]
const person = parsePeople(people)
console.log(person) -> Object
Using recursion we check if people is an instance of Array, we call the function again using people.pop() which return the last element of the array.
you have an array on your person data... you can only access that without the 0 using map...
example:
componentWillReceiveProps = (nextProps) => {
var PersonID = nextProps.person ? nextProps.person.map(item => { return item.PersonID}) : '';
var Name = nextProps.person ? nextProps.person.map(item => { return item.Name}) : '';
this.setState({
PersonID,
Name
});
}
this is considering you only have 1 array on person.
I fixed it! It was a combination of two of the answers given:
In the PersonPage.js, I had to call the PersonDetails object like this:
<PersonDetail
person={this.props.person[0]}
/>
And this is the new MapStatetoProps:
function mapStateToProps(state, props) {
const { match } = props;
if (match.params.PersonID) {
return {
person: state.people
}
}
Thanks to those who answered. This drove me nuts.