How can pull values from a Json in React? - reactjs

I'm trying to dosomething similar to this Angular Code but using React. I'm very new to react and can't figure it out.
I have a json that is storing data fields and a field called classes. I want to be able to pull the classes in json fields to attach them to each row. This is the angular way I have done in the past successfully.
<tr ng-repeat="row in vm.widget10.table.rows">
<td ng-repeat="cell in row">
<span class="{{cell.classes}}">
{{cell.value}}
</span>
</td>
</tr>
with a json structured this way
{
"widget10": {
"title": "Table Details",
"table": {
"columns": [{
"title": "Item Name"
},
{
"title": "Some Data"
},
{
"title": "Other Data ($)"
},
{
"title": "Visual Data (%)"
},
{
"title": "Profit/Loss ($)"
},
{
"title": "Profit/Loss (%)"
}
],
"rows": [
[{
"value": "Data Field One",
"classes": "text-boxed m-0 deep-orange-bg white-fg",
"icon": ""
},
{
"value": "$14,880.00",
"classes": "text-bold",
"icon": ""
},
{
"value": "$14,000.00",
"classes": "",
"icon": ""
},
{
"value": "%94.08",
"classes": "red-fg",
"icon": "trending_down"
},
{
"value": "$880.00",
"classes": "",
"icon": ""
},
{
"value": "%5.92",
"classes": "",
"icon": ""
}
]
]
}
}
In my react component render() I have something like this:
<TableBody
displayRowCheckbox={this.state.showCheckboxes}
deselectOnClickaway={this.state.deselectOnClickaway}
showRowHover={this.state.showRowHover}>
{statsData.map( (row, index) => (
<TableRow key={index}>
<TableRowColumn><span style={{backgroundColor:"{statsData.bgColor[index]}"}}>{row.name}</span></TableRowColumn>
<TableRowColumn>{row.data}</TableRowColumn>
<TableRowColumn>{row.o_data}</TableRowColumn>
<TableRowColumn>{row.v_data}</TableRowColumn>
<TableRowColumn>{row.o_pl}</TableRowColumn>
<TableRowColumn>{row.v_pl}</TableRowColumn>
</TableRow>
))}
</TableBody>
and a json this way (in the component)
const statsData = [
{
name: "Data Field One",
bgColor: "red",
data: "$14,880.00",
o_data: "$14,000.00",
v_data: "%94.08",
o_pl: "$880.00",
v_pl: "%5.92",
},
{
name: "Data Field Two",
bgColor: "blue",
data: "$14,880.00",
o_data: "$14,000.00",
v_data: "%94.08",
o_pl: "$880.00",
v_pl: "%5.92",
},
{
name: "Data Field Three",
bgColor: "yellow",
data: "$14,880.00",
o_data: "$14,000.00",
v_data: "%94.08",
o_pl: "$880.00",
v_pl: "%5.92",
}
];
So far the data comes through fine, but I can't figure out how to pull the bgColor as either a backgroundColor style or as a class.
Any help is appreciated.
Thanks

Remove the quotes from around the value for backgroundColor and read from the row iterator variable (based on the JSON you pasted):
<span style={{backgroundColor: row.bgColor}}>{row.name}</span>

Related

React - how to pass props with different names to same component

I have a card component that receives a title, description, and image props, however the data that I receive from two different sources labels these props differently.
Source 1 (carouselContent):
[
{
"id": "1",
"title": "title 1",
"description": "Description text 1",
"image": {
"fluid": {
"src": "/get-job-you-want.jpg?w=800&q=50"
}
}
},
{
"id": "2",
"title": "title 2",
"description": "Description text 2",
"image": {
"fluid": {
"src": "/framing-a-high-deck-1.jpg?w=800&q=50"
}
}
}
]
This passed onto an <ImageSlider/> component like so:
<ImageSlider data={carouselContent} />
Then next source (relatedPrograms) looks like this:
[
{
"fullProgramName": "title 1",
"id": "1",
"metaDescription": "description 1",
"heroImage": {
"fluid": {
"src": "/denys-nevozhai-100695.jpg?w=350&h=196&q=50&fit=scale"
}
}
},
{
"fullProgramName": "title 2",
"id": "2",
"metaDescription": "description 2",
"heroImage": null
}
]
and to be called like so:
<ImageSlider data={relatedPrograms} />
How do I structure the component to be able to handle both the title and image coming from source 1 and the fullProgramName and heroImage coming from source 2?
Here's a quick suggestion on how to map your two data sources to have a common shape. Obviously you'd modify this to contain the properties that were important to your ImageSlider component that renders the images. Here I have just picked a couple fields from your example data. The important feature here is that no matter where the data come from (carousel versus related), you transform them to represent a set of images, where their origin doesn't matter and they are indistinguishable to the ImageSlider. ImageSlider probably just cares about relevant image data, so decide on a shape that represents your basic image data.
Also a codesandbox for this: https://codesandbox.io/s/dank-morning-obwld
const normalizedCarousel = carouselContent.map((item) => ({
id: item.id,
name: item.title,
src: item.image.fluid.src
}));
const normalizedRelated = relatedPrograms.map((item) => ({
id: item.id,
name: item.fullProgramName,
src: item.heroImage?.fluid.src
}));
const ImageSlider = ({ header, data }) => {
// This component now just renders a list with relevant props
// but in the real app would render the slider.
return (
<>
<h2>{header}</h2>
<ul>
{data.map((item) => {
const { id, name, src } = item;
return (
<li>
Id: {id}, Name: {name}, Src: {src}
</li>
);
})}
</ul>
</>
);
};
export default function App() {
return (
<>
<ImageSlider header="Carousel" data={normalizedCarousel} />
<ImageSlider header="Related" data={normalizedRelated} />
</>
);
}
Either you can preprocess or combine your data just before passing it as a prop to your component or you can use a secondary prop and populate only the values from your secondary data source.
const a =[
{
"id": "1",
"title": "title 1",
"description": "Description text 1",
"image": {
"fluid": {
"src": "/get-job-you-want.jpg?w=800&q=50"
}
}
},
{
"id": "2",
"title": "title 2",
"description": "Description text 2",
"image": {
"fluid": {
"src": "/framing-a-high-deck-1.jpg?w=800&q=50"
}
}
}
]
const b = [
{
"fullProgramName": "title 1",
"id": "1",
"metaDescription": "description 1",
"heroImage": {
"fluid": {
"src": "/denys-nevozhai-100695.jpg?w=350&h=196&q=50&fit=scale"
}
}
},
{
"fullProgramName": "title 2",
"id": "2",
"metaDescription": "description 2",
"heroImage": null
}
]
const c = []
a.forEach((val, idx) => {
c.push({
title: val.title,
image: val.image,
fullProgramName: b[idx].fullProgramName,
heroImage: b[idx].heroImage
});
})
Then you can easily pass that copy of data to your component

Creating carousel from JSON response

I am getting a JSON response from a server which looks like this:
{
"value_1": "a",
"value_2": "b",
"pagination": {
"titles": [
"Title 1",
"Title 2",
"Title 3",
"Title 4",
"Title 5"
]
},
"slides": [
{
"pagination_id": 0,
"content": {
"heading": "Welcome!",
"description": "Stuff goes here",
"image": {
"url": "<image_url>",
"alt": "alternative text"
},
"next": {
"label": "Next"
}
}
},
{
"pagination_id": 1,
"content": {
"heading": "About",
"description": "Stuff goes here",
"image": {
"url": "<image_url>",
"alt": "alternative text"
},
"next": {
"label": "Next"
}
}
},
{
"pagination_id": 2,
"content": {
"heading": "Welcome!",
"description": "Stuff goes here",
"groups": [
{
"id": 1,
"label": "Group 1"
},
{
"id": 2,
"label": "Group 2"
},
{
"id": 3,
"label": "Group 3"
}
],
"next": {
"label": "Next"
}
}
},
{
"pagination_id": 3,
"heading": "Welcome!",
"description": "Stuff goes here",
"image": {
"url": "<image_url>",
"alt": "alternative text"
},
"back": {
"label": "Back"
},
"next": {
"label": "Next"
}
},
{
"pagination_id": 4,
"heading": "Welcome!",
"description": "Stuff goes here",
"image": {
"url": "<image_url>",
"alt": "alternative text"
},
"back": {
"label": "Back"
},
"next": {
"label": ""
}
}
],
"footer": {
"legal": {
"label": "Legal",
"url": "<url>"
},
"privacy": {
"label": "Privacy",
"url": "<url>"
},
"cookies": {
"label": "Cookies",
"url": "<url>"
}
}
}
As you can probably tell this data is being used to create a carousel with the slide content shown on each slide. The problem I am having is that the slide titles are coming from the pagination part of the JSON but the actual slide content including next and back buttons are coming from the slides part.
Currently I have some problems:
I need to get the correct title for each slide.
I need to render buttons based on the next and back properties present in each slide.
When a button is clicked to go forward or back I need to keep track of the slide that should be showing.
I already know that what I need to do for part 1 is use the pagination_id of the slide to get the correct title from the pagination.titles array but I am not entirely sure about the best way to go about this.
For the second part, I think it should be possible to also use the pagination_id to keep a track of the current slide (I think), but I am not sure how I might go about this. I should mention that the buttons for each slide are going to be render based on the next and back properties of each slide.
This application is built with React and I am currently only using local state currently as I don't think that something like Redux is really worth including for such a small amount of data.
Any help with this conundrum would be much appreciated,
Thanks for your time
In your case despite the data coming from different arrays, what you can cash around is that the number of items are the same in both arrays. So you can just use the current index of array where you are looping these items. So it would go something like this:
Updated Code
return(
data.slides.map((slide, index)=>{
return <div key={index}>
<h1> {data.pagination.titles[index]} </h1> // for title
<img src={slide.content?.image?.url || slide.image.url} alt={slide.content?.image?.alt || slide.image.alt} />
//for buttons
{(slide.content?.previous || slide.previous) && <button onClick={()=> setCurrentSlideIndex((index - 1) % data.slides.length)}> {slide.content?.previous?.label || slide.previous.label} </button>}
{(slide.content?.next || slide.next) && <button onClick={()=> setCurrentSlideIndex((index + 1) % data.slides.length)}> {slide.content?.next?.label || slide.next.label} </button>}
</div>
})
)
Hope you get the idea.
Update
However if there is lot of stuff going on then you might need to make a function which gets boolean as a parameter telling whether the particular item has content object or not, and return the ui based on that conditionally. Something like this:
const renderSlide=(content, index)=>{
if(content){
return <div>
// with slide.content.xyz
<h1> data.pagination.titles[index] </h1>
<img src={data.slides[index].content.image.url}
</div>
}
else{
return <div>
// with slide.xyz
<img src={data.slides[index].image.url}
</div>
}
}
and calling it inside your function as:
return(
data.slides.map((slide, index)=>{
<>
{renderSlide(slide.content, index)}
<>
})

React table with JSON subdocument data only

I have nested arrays in JSON object that comes from CosmosDB. I have 3 subdocuments in the JSON which I want to display that data into a react table for each subdocument. How can we map each subdocument to a React Table Rows?
Below is the screenshot that I am expecting.
below is JSON data
[
{
"id": "DD3",
"studydate": "DDD",
"studydescription": "DD3 Description",
"studyname": "DD3",
"table1": [
{
"no": "1",
"name": "DD3 Name",
"date": "Krishna",
"description\r": "1111\r"
},
{
"no": "2",
"name": "DD3 Nam2",
"date": "Test2",
"description\r": "2222\r"
},
{
"no": "3",
"name": "DD3 Name3",
"date": "Test3",
"description\r": "3333"
}
],
"table2": [
{
"No": "2",
"Study Field1": "21",
"Study Field2": "22",
"Study Field3\r": "23"
}
],
"table3": [
{
"No": "3",
"Study Field5": "T31",
"Study Field6": "T32",
"Study Field7": "T33",
"Study Field 8\r": "T34"
}
],
"_rid": "QeNcANZFTTIKAAAAAAAAAA==",
"_self": "dbs/QeNcAA==/colls/QeNcANZFTTI=/docs/QeNcANZFTTIKAAAAAAAAAA==/",
"_etag": "\"33002e92-0000-0200-0000-5fa6fe320000\"",
"_attachments": "attachments/",
"_ts": 1604779570
}
]
I have a basic example of how you could generate the rows off JSON. I am just using basic HTML to keep it simple as the prop names will change depending what component you go with but same principle.
JavaScript for filtering and pushing to table array.
let rowArr = [];
Object.keys(data).forEach(function(key) {
rowArr.push(data[key])
})
HTML/JS
<table>
<!-- This should loop through rows allowing you to get row values -->
{rowArr.map(row => (
<tr key={row}>
<td>{row.Task}</td>
<td>{row.Description}</td>
<td>{row.Assignee}</td>
<td>{row.Client}</td>
<td>{row.Contact}</td>
</tr>
))}
</table>
Here is a simple JSON structure
let data =
{
1:{
Task: "Software",
Description: "Mockup designs",
Assignee: "John Doe",
Client: "Mark Wong",
Contact: "mark.wong#gmail.com"
}
}

react 16, render with array, with first and last element conditiona with divl in complex render

I have a render that returns array and it's working well, it's iterate over an array to show fields in a form. But now i Want to enclose in a divs to group some fields conditionnaly accord to a propery. to get somethi like
<div class='section>
<Field>
<Field>
</div>
<div class='section>
<Field>
</div>
actually i get just:
<div class='section>
<Field>
<Field>
</div>
One example of a branch in my object:
(it's when the field have "formNewSection" property to separate the fields grouped by div)
"identitydocs": {
"type": "String",
"dbtype": "Json",
"labelChildsGlobal": true,
"labelChildsShow": true,
"subfields": {
"id": {
"type": "ID",
"typeInput": "hidden"
},
"type": {
"type": "String",
"label": "id_doctype"
},
"country": {
"type": "String",
"validators": [
"required"
],
"typeInput": "selectBox",
"listSource": "countries"
},
"number": {
"type": "String",
"label": "id_docnumber"
},
"idnameisother": {
"type": "Boolean",
"typeInput": "checkbox",
"formNewSection": true
},
"lastname": {
"type": "String",
"validators": [
"required",
"alphai18n",
"minLength:3"
],
"normalize": "UpperCase"
},
"firstname": {
"type": "String",
"validators": [
"required",
"alphai18n",
"minLength:3"
]
},
"idexpiration": {
"type": "String",
"dbtype": "Date"
},
"idiauthority": {
"type": "String"
},
"ididate": {
"type": "String",
"dbtype": "Date"
},
"idaddressisother": {
"type": "Boolean",
"typeInput": "checkbox",
"formNewSection": true
},
"addressline1": {
"type": "String",
"validators": [
"required"
]
},
"addressline2": {
"type": "String",
"validators": [
"required"
]
},
"cp": {
"type": "String",
"inputSize": 7
},
"city": {
"type": "String"
},
"cityid": {
"type": "ID",
"typeInput": "hidden"
}
}
},
My code working:
return [
<Field
key={index+'-'+subindex+'-'+fieldKey}
name={`${rowValues}.${fieldKey}`}
type={subfield.typeInput ? subfield.typeInput : 'text'}
typeInput={subfield.typeInput ? subfield.typeInput : 'text'}
component={FormField}
label={field.labelChildsShow ? t(labelKey ):''}
placeHolder={!field.labelChildsShow || subfield.placeHolder ? t(labelKey) : ''}
listSource={subfield.listSource ? aSources[subfield.listSource] : ''}
index={subindex + 1}
width="270px"
icon={subfield.icon}
/>,
fields.length === 1 && subindex + 1 === Object.keys(Tables[tableCrud].fields[fieldParentKey].subfields).length ?
<div key={index+'-'+subindex+'-b'} style={ { marginTop: "10px", marginRight: "5px" } }><a href="#" onClick={() => fields.remove(index)}>
<ShowIcon size="25" color="gray" icon="removecircleblack"/>
</a></div>
: null,
];
My new codigo does not work, adding and on the top and botomm of array but conditionnaly:
return [
(subfield.formNewSection && <div className="formSubSection" >),
<Field
key={index+'-'+subindex+'-'+fieldKey}
name={`${rowValues}.${fieldKey}`}
type={subfield.typeInput ? subfield.typeInput : 'text'}
typeInput={subfield.typeInput ? subfield.typeInput : 'text'}
component={FormField}
label={field.labelChildsShow ? t(labelKey ):''}
placeHolder={!field.labelChildsShow || subfield.placeHolder ? t(labelKey) : ''}
listSource={subfield.listSource ? aSources[subfield.listSource] : ''}
index={subindex + 1}
width="270px"
icon={subfield.icon}
/>,
(fields.length === 1 && subindex + 1 === Object.keys(Tables[tableCrud].fields[fieldParentKey].subfields).length ?
<div key={index+'-'+subindex+'-b'} style={ { marginTop: "10px", marginRight: "5px" } }><a href="#" onClick={() => fields.remove(index)}>
<ShowIcon size="25" color="gray" icon="removecircleblack"/>
</a></div>
: null)
(subfield.formNewSection && </div>),
];
with this modificaiotn i get print "fields.length === 1 && subindex + 1 === ..." on the screen.
is possible to do what i'm looking for with react? I can't do it in a simple way, becase this render is inside another render do it with .map, some fields have a mark to be grouped by divs and anothers not, so i can't see for the simple solutions
Could you provide the array structure or the real data for the data I'll take a look and see If I can help you with that.
One idea is suppose you had a a data structure housing the the items with index or a length that is equivalent to the fields something like this:
{
0: [ ... , ]
... to whatever data length
} <-- this can be an array instead of object
iterate over this container/w.e and have a div surrounding it
pending if you used array or object if object you can use Object.keys(w.e)
like poopArrayContainer.map( (item,ind) => { item.map( poop => ... ) } ) ... pretty sure you get it from here hope that helps, not sure of that's the best implementation but that's a thot LuL...
Why not just add the div tag before the field one and at the end like :
<div className="formSubSection" > <Field.......
..
</a></div></div>
: null)

Ng-repeat angular js

I have my json from the server as
[
{
"guid":"54db86c947b39358ab2c266a",
"modified":0,
"created":0,
"name":"iOS",
"criteria":[
{
"name":"Supportability",
"value":1,
"reasons":[
"we do not know the tech"
]
},
{
"name":"Core Image",
"value":1,
"reasons":[
"Some reason",
"Reason 2"
]
},
{
"name":"Deployment",
"value":1,
"reasons":[
"no servers"
]
},
{
"name":"Hardware",
"value":1,
"reasons":[
"hardware too expensive"
]
},
{
"name":"Security",
"value":1,
"reasons":[
"plain text password"
]
},
{
"name":"Application",
"value":0.85,
"reasons":[
"332 out of 1600 apps are not package for W10"
]
}
],
"type":"Software"
},
{
"guid":"54db81ab47b3187eceaef46e",
"modified":0,
"created":0,
"name":"Windows 8",
"criteria":[
{
"name":"Supportability",
"value":1,
"reasons":[
"we do not know the tech"
]
},
{
"name":"Core Image",
"value":1,
"reasons":[
"Some reason",
"Reason 2"
]
},
{
"name":"Deployment",
"value":1,
"reasons":[
"no servers"
]
},
{
"name":"Hardware",
"value":1,
"reasons":[
"hardware too expensive"
]
},
{
"name":"Security",
"value":1,
"reasons":[
"plain text password"
]
},
{
"name":"Application",
"value":0.405,
"reasons":[
"332 out of 1600 apps are not package for W10"
]
}
],
"type":"Software"
},
{
"guid":"54db81ab47b3187eceaef46f",
"modified":0,
"created":0,
"name":"Windows 10.1",
"criteria":[
{
"name":"Supportability",
"value":1,
"reasons":[
"we do not know the tech"
]
},
{
"name":"Core Image",
"value":1,
"reasons":[
"Some reason",
"Reason 2"
]
},
{
"name":"Deployment",
"value":1,
"reasons":[
"no servers"
]
},
{
"name":"Hardware",
"value":1,
"reasons":[
"hardware too expensive"
]
},
{
"name":"Security",
"value":1,
"reasons":[
"plain text password"
]
},
{
"name":"Application",
"value":0.85,
"reasons":[
"332 out of 1600 apps are not package for W10"
]
}
],
"type":"Software"
}
]
How do i use ng-repeat in table so that I get the table as
<th>Criteria</th>
<th>iOs</th>
<th>windows</th>..(basically json.name)
and my table body as
<tr>
<td>Supportability (json.criteria[0].name)</td>
<td>1</td>(value for iOs)
<td>1</td>(value for Windows10.1)
<td>...................and so on.
</tr>
<tr><td>Core Image</td>
<td>1</td> ......
</tr>
?
As other comments have said, this data structure is not suitable for tables. Not optimal this way either, but if you really want to, you can manage it using divs. But you have to use multiple ng-repeats over the same data (not good).
<div class="section">
<div class="header"> </div>
<div class="body" ng-repeat="y in mydata[0].criteria">
{{y.name}}
</div>
</div>
<div class="section" ng-repeat="x in mydata">
<div class="header">{{x.name}}</div>
<div class="body" ng-repeat="y in x.criteria">
{{y.value}}
</div>
</div>
plunkr: http://plnkr.co/edit/FpsTe36oYh5t6a0XI2Dc?p=preview
I'll say it again, you're better off restructuring your data to suit your output.

Resources