Mapping an array inside an object inside an array - reactjs

I am having trouble displaying a pair of options for the corresponding prompt.
I made a .json file to hold the prompts and options.
This is the dataset:
[
{
"id": 1,
"text": "hey wut r u doin",
"options": [
{
"id": 1,
"text": "Playing Pokemon",
"nextPrompt": 2
},
{
"id": 2,
"text": "Watching a movie",
"nextPrompt": 7
}
]
},
{
"id": 2,
"text": "lol you still play that??",
"options": [
{
"id": 1,
"text": "It's fun!",
"nextPrompt": 18
}
{
"id": 2,
"text": "Just kidding ha ha...",
"nextPrompt": 7
}
}]
In the component I'm trying to go to the currentPrompt, look at the options and then from there map the text. When I console.log(currentPrompt.options) it says undefined... Why is that?
This is my component:
function PromptsAndOptions() {
const [currentPrompt, setCurrentPrompt] = useState(POA[0].text);
return (
<section>
<section>{currentPrompt}</section>
{console.log(currentPrompt)}
<section>
{currentPrompt.options &&
currentPrompt.options.map(({ text }) => (
<button key={currentPrompt.options.id}>{text}</button>
))}
</section>
</section>
);
}

I think your JSON file is wrong
Try the CodeSandBox
const POA = [
{
id: 1,
text: "hey wut r u doin",
options: [
{
id: 1,
text: "Playing Pokemon",
nextPrompt: 2
},
{
id: 2,
text: "Watching a movie",
nextPrompt: 7
}
]
},
{
id: 2,
text: "lol you still play that??",
options: [
{
id: 1,
text: "It's fun!",
nextPrompt: 18
},
{
id: 2,
text: "Just kidding ha ha...",
nextPrompt: 7
}
]
}];
const [id, setId] = useState(1);
const promp = POA[id].options;
return (
<section>
<section>{id}</section>
{console.log(id)}
<section>
{promp &&
promp.map((item, i) => {
return (
<>
<div key={i}>Items Text Is === {item.text}</div>
<br />
</>
);
})}
<div onChange={(e) => setId(e.target.value)}>
<input type="radio" value="0" name="gender" /> First
<input type="radio" value="1" name="gender" /> Second
</div>
</section>
</section>);

Related

React 18.2.0-style property not rendering image

I am currently working through the ZTM React course version 18.2.0 in Udemy. For whatever reason, posting questions has been disabled on Udemy website so I am posting here. The following code renders fine when I run it-all except for the images. The image url is valid when put into a browser. There are no other errors whatsoever. The only issue is that the image is not showing.
import "./categories.styles.scss"
//import CategoryItem from "./components/category-item/category-item.component";
const App = () => {
const categories = [
{
"id": 1,
"title": "hats",
"imageUrl": "https://i.ibb.co/cvpntL1/hats.png"
},
{
"id": 2,
"title": "jackets",
"imageUrl": "https://i.ibb.co/px2tCc3/jackets.png"
},
{
"id": 3,
"title": "sneakers",
"imageUrl": "https://i.ibb.co/0jqHpnp/sneakers.png"
},
{
"id": 4,
"title": "womens",
"imageUrl": "https://i.ibb.co/GCCdy8t/womens.png"
},
{
"id": 5,
"title": "mens",
"imageUrl": "https://i.ibb.co/R70vBrQ/men.png"
}
];
return (
<div className="categories-container">
{categories.map(({title,id,imageUrl}) => (
<div key={id} className="category-container">
<div
className='background-image'
style={{
backgroundImage: `url(${imageUrl})`
}}>
</div>
<div className='category-body-container'>
<h2>{title}</h2>
<p>Shop Now</p>
</div>
</div>
))}
</div>
);
};
export default App;
Your categories should be an array of objects like this
const categories = [
{
id: 1,
title: 'hats',
imageUrl: 'https://i.ibb.co/cvpntL1/hats.png',
},
{
id: 2,
title: 'jackets',
imageUrl: 'https://i.ibb.co/px2tCc3/jackets.png',
},
{
id: 3,
title: 'sneakers',
imageUrl: 'https://i.ibb.co/0jqHpnp/sneakers.png',
},
{
id: 4,
title: 'womens',
imageUrl: 'https://i.ibb.co/GCCdy8t/womens.png',
},
{
id: 5,
title: 'mens',
imageUrl: 'https://i.ibb.co/R70vBrQ/men.png',
},
];
Your example of categories above is json-like
Also, the links are not working. Try download the images locally

How can I filter my json object by id in react

Hi this is my first question.
I want to filter my json object by id
This is the JSON file code I pasted below:
[
{
"id": 1,
"name": "Class 1",
"sub_informations": [
{
"id": 1,
"name": "John",
"sex": "male",
"user": 1,
},
{
"id": 2,
"name": "Agatha",
"sex": "female",
"user": 1,
}
]
},
{
"id": 2,
"name": "Class 2",
"sub_informations": [
{
"id": 3,
"name": "Ben",
"sex": "male",
"user": 2,
}
]
}
]
what I want is to be able to put the sub_informations elements in the li tag according to the id.
That is, I want to bring the name and gender information of class 1 to my first li tag, and the name and gender information of class 2 to my second li tag.
How can i write this in code?
import React from 'react'
import user from 'api/users.json'
import { useState, useEffect } from 'react';
export default function App() {
const [users, setUsers] = useState([])
useEffect(() => {
setTimeout(() =>setUsers (user),1000)
return (
<>
{users.map((index, i) => {
<ul>
<li>{index.id[1]}</li>
<li>{index.id[2]}</li>
</ul>
})}
</>
)
}
i understand you can make list by id. I belive you can do so like this :
return (
<>
{users.map((index, i) => {
<ul>
{
index.id === 1 &&
(
<>
<h1>{index.name}</h1>
{
index.sub_informations.map((sub, ind) => {
<li>
{sub.name + " " + sub.sex}
</li>
})
}
</>
)
}
{
index.id === 2 &&
(
<>
<h1>{index.name}</h1>
{
index.sub_informations.map((sub, ind) => {
<li>
{sub.name + " " + sub.sex}
</li>
})
}
</>
)
}
</ul>
})}
</>
If this doesn't what you want to do , please tell us more information for we can help you.
Assuming that OP needs to list down the sub_information under a list for each user entry/object, the below solution may achieve this assumed objective:
Code Snippet
const Thingy = ({users, ...props}) => {
return (
<div>
{users.map(u => (
<ul>
{u.name}
{u["sub_informations"].map(si => (
<li>
{si.id} {si.name} {si.sex}
</li>
))}
</ul>
))}
</div>
);
};
const rawData = [{
"id": 1,
"name": "Class 1",
"sub_informations": [{
"id": 1,
"name": "John",
"sex": "male",
"user": 1,
},
{
"id": 2,
"name": "Agatha",
"sex": "female",
"user": 1,
}
]
},
{
"id": 2,
"name": "Class 2",
"sub_informations": [{
"id": 3,
"name": "Ben",
"sex": "male",
"user": 2,
}]
}
];
ReactDOM.render(
<div>
DEMO
<Thingy users={rawData}/>
</div>,
document.getElementById("rd")
);
<div id="rd" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
Explanation
Iterate over users array
For each user, iterate over sub_information array
For each element, render it's props (such as id, name, sex, etc)
OP needs to clarify if this is not what they desired to achieve.
The following results in a nested list by using map twice to iterate once of the users and once over the sub_informations.
const myUsers = [
{
"id": 1,
"name": "Class 1",
"sub_informations": [
{
"id": 1,
"name": "John",
"sex": "male",
"user": 1,
},
{
"id": 2,
"name": "Agatha",
"sex": "female",
"user": 1,
}
]
},
{
"id": 2,
"name": "Class 2",
"sub_informations": [
{
"id": 3,
"name": "Ben",
"sex": "male",
"user": 2,
}
]
}
];
function App() {
const [users, setUsers] = React.useState(myUsers);
return (
<ul>
{users.map((user) => {
if (!user.sub_informations) {
return (
<li>
{user.id} || {user.name}
</li>
);
} else {
return (
<React.Fragment>
<li>
{user.id} || {user.name}
</li>
<ul>
{user.sub_informations.map((info) => (
<li>
{info.id} || {info.name} || {info.sex} || {info.user}
</li>
))}
</ul>
</React.Fragment>
);
}
})}
</ul>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Note: Some slight adjustments to your code where necessary to be able to put this in a snippet.

React: How to render a list of items grouped by category (using .map)

I have an array (myArray), stored like so (in firebase):
[
{
"id": "1",
"Category": "Hardware",
"Name": "Xtreme"
},
{
"id": "123",
"Category": "Software",
"Name": "Obsolete"
},
{
"id": "12345",
"Category": "Software",
"Name": "V1"
},
{
"id": "1234567",
"Category": "Hardware",
"Name": "CPU"
}
]
I am using the following code:
const sorterAR = [];
myArray.forEach((item) => {
let cat = sorterAR.find(
(cat) => cat.id === item.id
);
if (!cat) {
cat = {
id: item.id,
Category: item.Category,
items: [],
};
sorterAR.push(cat);
}
cat.items.push(item);
});
And then displaying like so:
<div className="App">
{sorterAR.map((cat) => (
<>
<div>
<b>{cat.Category}</b>
</div>
<ul>
{cat.items.map((item) => (
<li>{item.Name}</li>
))}
</ul>
</>
))}
</div>
This works in that it produces an output like:
**Hardware**
Xtreme
**Hardware**
CPU
**Software**
Obsolete
**Software**
V1
How do I alter this to produce the following output:
**Hardware**
Xtreme
CPU
**Software**
Obsolete
V1
So that it displays the category name and then all the items in that category, and then moves to the next one and so forth?
I assumed that order doesn't matter if Hardware or Software should come first.
First I categorized the array into an object of Category objects using Array.prototype.reduce().
From the resultant object you can build the JSX
var data1 = [
{
id: '1',
Category: 'Hardware',
Name: 'Xtreme',
},
{
id: '123',
Category: 'Software',
Name: 'Obsolete',
},
{
id: '12345',
Category: 'Software',
Name: 'V1',
},
{
id: '1234567',
Category: 'Hardware',
Name: 'CPU',
},
];
const categorizedData = data1.reduce((acc, curr) => {
const { id, Category, Name } = curr;
if (!acc[Category]) {
acc[Category] = {
items: [],
};
}
acc[Category].items.push(Name);
return acc;
}, {});
console.log(categorizedData);
Object.keys(categorizedData).map((key, index) => {
console.log(`Category: ${key}`);
categorizedData[key].items.map((item, index) =>
console.log(`Item ${index}: ${item}`)
);
});

How to search and filter in array of objects on setState

I'm trying to create a search based on an array of objects with react which data is in this format:
const data = [
{"category 1" : [
{
"name": "Orange",
"desc": "juice, orange, Water"
},
{
"name": "Ananas",
"desc": "juice, ananas, water"
}
]
},
{"category 2" : [
{
"name": "Banana Split",
"desc": "Banana, ice cream, chocolat, topping",
"allergens": "nuts"
},
{
"name": "Mango Sticky Rice",
"desc": "Mango, rice, milk",
"allergens": ""
}
]
}
]
I stored this data inside useState declaration to be able to render accordingly on data chnage:
const [filteredBySearch, setFilteredBySearch] = useState(data)
I have an input where we can type anything and set inside useState declaration.
Goal:
If I type in my input:
"Jui"
Output should be:
console.log(filteredBySearch)
/* output:
[
{"category 1" : [
{
"name": "Orange",
"desc": "juice, orange, Water"
},
{
"name": "Ananas",
"desc": "juice, ananas, water"
}
]
},
{"category 2" : []
}
]*/
Exemple 2:
If I type in my input:
"Orange banana"
Output should be:
console.log(filteredBySearch)
/* output: [
{"category 1" : [
{
"name": "Orange",
"desc": "juice, orange, Water"
}
]
},
{"category 2" : [
{
"name": "Banana Split",
"desc": "Banana, ice cream, chocolat, topping",
"allergens": "nuts"
}
]
}
]*/
I've try creating a new object with map and filter and set it with setFilteredBySearch, but I can't get anything, even creating this new object.
This the full component:
import Card from '../components/Card'
import React, { useState } from 'react';
export default function IndexPage({ data, search }) {
//search is the result of input value set on a useState
//Filter categoriesFoods by search
const [FilteredBySearch, setFilteredBySearch] = useState(data)
return (
<div className="main-content">
<div className="card-container">
{
FilteredBySearch.map(function(el, i) {
return (
<div key={i}>
<h2 className="category" id={Object.keys(el)}>{Object.keys(el)}</h2>
{
el[Object.keys(el)].map (function(itm,index){
return <Card key={index} infoItem={itm}/>
})
}
</div>
)
})
}
</div>
<style jsx>{`...`}</style>
</div>
)}
Any idea for me ?
Thanks a lot for your guidance!
I think this is what you are looking for. I have created below utilities for filtering as per your requirement.
const dataObj = [
{
'category 1': [
{
name: 'Orange',
desc: 'juice, orange, Water',
},
{
name: 'Ananas',
desc: 'juice, ananas, water',
},
],
},
{
'category 2': [
{
name: 'Banana Split',
desc: 'Banana, ice cream, chocolat, topping',
allergens: 'nuts',
},
{
name: 'Mango Sticky Rice',
desc: 'Mango, rice, milk',
allergens: '',
},
],
},
]
const checkIfInputMatches = (input, desc) => input.toLowerCase().split(" ").some(o => desc.toLowerCase().includes(o))
const filterByInput = (data, input) => {
let finalResult = [];
data.forEach(d => {
let keys = Object.keys(d);
let values = Object.values(d);
finalResult = [...finalResult, ...values.map((obj, index) => {
let result = obj.filter(o => checkIfInputMatches(input, o.desc))
return {[keys[index]]: result}
})]
})
return finalResult
}
console.log(filterByInput(dataObj, 'JUI'))
console.log(filterByInput(dataObj, "orange"))
console.log(filterByInput(dataObj, "rice"))
console.log(filterByInput(dataObj, "Orange banana"))
Hope this helps.

Number input within a React Mapped Array

I'm currently working on my first react App and I'm having a little trouble with a product list that I'm trying to create.
Essentially I'm trying to create a list (parsed into react from a JSON file) which will enable the user to select the number of products that they want.
However the quantity selector that I have created is updating all of the iterations of the mapped array rather than just the one that the selector is inside of. How can I adjust the code so that only one counter updates at a time?
My Code is as follows
import React, { Component } from "react";
import "./App.css";
import productdata from "./catalog.json";
class App extends Component {
constructor(props) {
super(props);
this.state = {
BundleVal: "",
ProductVal:"",
CounterVal: 0
}
}
updateBundle = (val) => {
this.setState({
BundleVal: val
})
};
updateProduct = (val) => {
this.setState({
ProductVal: val
})
};
counterincrease = (val) => {
this.setState({
CounterVal: this.state.CounterVal + 1
})
};
counterdecrease = (val) => {
this.setState({
CounterVal: this.state.CounterVal - 1
})
};
render() {
const BundleProducts = [].concat(productdata.data.products).map((item, i) =>
<div key={item.id}>
{item.id} <br />
{item.name} <br />
{item.description} <br />
Installation: {item.price.installation} <br />
Monthly: {item.price.recurring} <br />
{this.state.CounterVal}
<button onClick={this.counterincrease}>+</button>
<button onClick={this.counterdecrease}>-</button>
</div>
);
let bname = null;
if (this.state.BundleVal === "1") {
bname = "Bundle 1";
}
else if (this.state.BundleVal === "2") {
bname = "Bundle 2";
}
else if (this.state.BundleVal === "3") {
bname = "Bundle 3";
}
else if (this.state.BundleVal === "4") {
bname = "Bundle 4";
}
else {bname = null;}
return (
<div>
<h2>Order</h2>
Bundle Id: {this.state.BundleVal}
<br/>
Chosen Bundle: {bname}
<br/>
Number of Products: {this.state.ProductVal}
<br/>
<Bundle updateBundle={this.updateBundle} />
{BundleProducts}
</div>
)
}
}
class Bundle extends React.Component {
constructor(props) {
super(props);
this.state = {
BundleVal: ""
}
}
updatebundle = (e) => {
this.props.updateBundle(e.target.value);
this.setState({BundleVal: e.target.value});
};
render() {
return (
<div>
<h4>Bundle</h4>
<input
type="radio"
value="1"
onChange={this.updatebundle}
checked={this.state.BundleVal==='1'}
/> Bundle 1
<input
type="radio"
value="2"
onChange={this.updatebundle}
checked={this.state.BundleVal==='2'}
/> Bundle 2
</div>
)
}
}
export default App;
Some code from my JSON file is included below
{
"timestamp": 1502121471,
"data": {
"adverts": [],
"bundles": [{
"id": "1",
"name": "Bundle 1",
"description": "Bundle 1 Description",
"maximumPeripherals": 32,
"available": true,
"count": 0,
"price": {
"installation": "99.99",
"recurring": "23.99"
},
"image": {
"file": "bundle-one.png",
},
"products": ["1", "2", "3"]
}, {
"id": "2",
"name": "Bundle 2",
"description": "Bundle 2 Description",
"maximumPeripherals": 32,
"available": true,
"count": 0,
"price": {
"installation": "99.99",
"recurring": "23.99"
},
"image": {
"file": "bundle-two.png",
},
"products": ["1", "2", "2", "2", "2"]
}],
"products": [{
"id": "1",
"name": "Product 1",
"description": "Product 1 Description",
"maximumQuantity": 1,
"isPeripheral": false,
"isAvailable": true,
"price": {
"upfront": null,
"installation": "0.00",
"recurring": "0.00"
},
"image": {
"file": "product-one.png",
}
}, {
"id": "2",
"name": "Product 2",
"description": "Product 2 Description",
"maximumQuantity": null,
"isPeripheral": true,
"isAvailable": true,
"count": 0,
"price": {
"upfront": "60.00",
"installation": "9.60",
"recurring": "1.25"
},
"image": {
"file": "product-two.png",
}
}, {
"id": "3",
"name": "Product Three",
"description": "Product Three Description",
"maximumQuantity": null,
"isPeripheral": true,
"isAvailable": true,
"count": 0,
"price": {
"upfront": "132.00",
"installation": "9.60",
"recurring": "2.75"
},
"image": {
"file": "product-three.png",
}
}]
}
}
A friend of mine suggested the following to answer this question. Essentially the array will now loop through the values and add a different id will be applied to each input.
updateQuantity = (e) => {
var pCounter = this.state.ProductCounter;
var el = parseInt(e.target.id.split("_")[1], 10);
pCounter[el] = parseInt(e.target.value, 10);
this.setState({ProductCounter: pCounter});
console.log(this.state.ProductCounter);
};
render() {
const BundleProducts = [].concat(productdata.data.products).map((item, i) =>
<div key={item.id}>
{item.id} <br />
{item.name} <br />
{item.description} <br />
Installation: {item.price.installation} <br />
Monthly: {item.price.recurring} <br />
<input
type="number"
onChange={this.updateQuantity}
value={this.state.ProductCounter[item.id] || 0}
id={"product_"+item.id}
/><br />
{this.state.ProductCounter[item.id] || 0}
<hr />
</div>
);

Resources