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>
);
Related
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>);
I have autocompleted features. when I search for something we will get the data accordingly. But I want to add one more feature like when we search data will come as well as whatever I typed in the search box that character should be highlighted in yellow color.
Here is the piece of code I have written.
import logo from './logo.svg';
import './App.css';
import React, { useState } from "react";
function App() {
const [names, setnames] = useState([{
"name": "Barbara-anne"
}, {
"name": "Debi"
}, {
"name": "Cara"
}, {
"name": "Cristin"
}, {
"name": "Jocelyne"
}, {
"name": "Joellyn"
}, {
"name": "Elmo"
}, {
"name": "Ivette"
}, {
"name": "Lea"
}, {
"name": "Michel"
}, {
"name": "Leigha"
}, {
"name": "Titus"
}, {
"name": "Nollie"
}, {
"name": "Celle"
}, {
"name": "Thea"
}, {
"name": "Brynn"
}, {
"name": "Sloane"
}, {
"name": "Margalo"
}, {
"name": "Genevieve"
}, {
"name": "Niel"
}, {
"name": "Heddi"
}, {
"name": "Gregg"
}, {
"name": "Eduard"
}, {
"name": "Kizzee"
}, {
"name": "Truman"
}, {
"name": "Merill"
}, {
"name": "Lindie"
}, {
"name": "Vasily"
}, {
"name": "Averil"
}, {
"name": "Golda"
}, {
"name": "Zorine"
}, {
"name": "Odele"
}, {
"name": "Amalie"
}, {
"name": "Ilsa"
}, {
"name": "Pepillo"
}, {
"name": "Hewe"
}, {
"name": "Byrann"
}, {
"name": "Alford"
}, {
"name": "Lanny"
}, {
"name": "Kristina"
}, {
"name": "Mar"
}, {
"name": "Vittoria"
}, {
"name": "Winslow"
}, {
"name": "Ashlan"
}, {
"name": "Gayelord"
}])
const [searchTerm, setSearchTerm] = useState('')
const filteredName=names.filter((val)=>{
if(searchTerm ===""){
return val;
}else if(val.name.toLowerCase().includes(searchTerm.toLowerCase())){
return val;
}
});
const renderStatementResult = searchTerm && searchTerm.length > 0;
return (
<>
<div className="srchField">
<label for="statement">Statement Name</label>
<div className="valueField">
<input type="text" name="fileName" id="statement" data-validate="true" placeholder="Type Name" onChange={event => {setSearchTerm(event.target.value)}}/>
{
renderStatementResult ? <ul className="lookup-results">
{filteredName.map((value)=>(<li key={value.name}>{value.name}</li>))}
</ul> : null
}
</div>
</div>
</>
);
}
export default App;
refer this image
Can anyone have an idea of how to match the highlighted text. I want to highlight all s in yellow color
Replace your map function with
filteredName.map((value) => {
let string = value.name.substr(
0,
value.name.toLowerCase().indexOf(searchTerm.toLowerCase())
);
let endString = value.name.substr(
value.name.toLowerCase().indexOf(searchTerm.toLowerCase()) +
searchTerm.length
);
let highlightedText = value.name.substr(
value.name.toLowerCase().indexOf(searchTerm.toLowerCase()),
searchTerm.length
);
return (
<li key={value.name}>
{string}
<span style={{ "background-color": "#FFFF00" }}>
{highlightedText}
</span>
{endString}
</li>
);
})
The first line( let string =...) extracts the part of string which comes before the part that should be highlighted, and the next line extracts the part after the highlight. The search term itself is kept in a span tag which is styled to highlight.
The above snippet only highlights the first occurrence of the search term, so if the search term is 's' and one of the names is 'Samson', only the first 's' would be highlighted. If you want to highlight all occurrences, then you can use regular expressions to find out the indices of all occurrences and loop across the indices, constructing your li tag along the way.
A working sandbox can be found at https://codesandbox.io/embed/elated-chandrasekhar-ggoi1?fontsize=14&hidenavigation=1&theme=dark
Try this
{filteredName.map((value)=>(<li key={value.name}>{
value.name.split('').map((char) => {
if (searchTerm.toLowerCase().split('').includes(char.toLowerCase())) {
return <span style={{ color: 'yellow' }}>{char}</span>;
} else {
return <span>{char}</span>;
}
})
}</li>))}
I have to map the nested JSON result in React. The below one is the response I got as response from backend API.
{
"id": 2,
"name": "sanjna",
"email": "vv#gmail.com",
"address": "iiiii, hhh",
"gender": "1",
"tagline": "Friendly to all",
"description": "4 years experience in programming",
"languages": "English ",
"key_skills": [
{
"id": 1,
"name": "RUBY ON RAILS, HTML, BOOTSTRAP, JQUERY, REACT",
"relevant_experience": "4"
},
{
"id": 2,
"name": "ruby",
"relevant_experience": "2"
}
],
"certifications": [
{
"id": 1,
"name": "MCA",
"institution_name": "vvv unversity",
"certification_date": "20-12-2020",
"image": null
},
{
"id": 2,
"name": "HTML training",
"institution_name": "nnn unversity",
"certification_date": "20-12-2022",
"image": null
}
],
"educations": [
{
"id": 1,
"qualification": "MCA",
"course": "Masters Degree PG",
"institute": "kkk",
"ins_location": "jjjj",
"passing_year": "2015"
}
]
}
This is my React code to get this response
const [singleUserDetail, setsingleUserDetail] = React.useState('');
let logged_user_id = job_seeker.actable_id;
const getsingleUserDetails = (logged_user_id) => {
axios
.get(`http://localhost:3001/users/${logged_user_id}`, { withCredentials: true })
.then((response) => {
const singleUserDetail = response.data;
setsingleUserDetail(response.data)
console.log(response.data); //prints the above JSON results in console
})
.catch((error) => {
console.log(" error", error);
});
};
React.useEffect(() => {
getsingleUserDetails(logged_user_id);
}, [logged_user_id]);
When I prints {singleUserDetail.name} it gives me result sanjna
{singleUserDetail.email} it gives me result vvv#gmail.com
{singleUserDetail. address} it gives me result iiiii, hhh. from my above JSON result
But how to print keyskills, certifications and educations here with mapping. I'm a beginner in React.
Youu can do something like this, my example is very simple,but you can complicate this as much as you need, with conditions or loops in loops.
<div>
{singleUserDetail.name},{singleUserDetail.email},{singleUserDetail.address},{singleUserDetail.gender},{singleUserDetail.tagline},{singleUserDetail.description}, {singleUserDetail.languages}
</div>
{singleUserDetail.key_skills.map((skill)=>{
return(
<div key={skill.id}>
{skill.name}:{skill.relevant_experience}
</div>
);
})}
{singleUserDetail.certifications.map((certification)=>{
return(
<div key={certification.id}>
{certification.name},{certification.institution_name},{certification.certification_date}
</div>
);
})}
{singleUserDetail.educations.map((education)=>{
return(
<div key={education.id}>
{education.qualification},{education.course},{education.institute}
</div>
);
})}
For more information, React documentation
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.
I can't seem to pass certain items into an item prop if they relate to the category that I am looping through
I have a JSON like this:
{
"Categories": [
{
"Name": "Music",
},
{
"Name": "Comedy",
},
{
"Name": "Sport",
},
{
"Name": "Family",
},
],
"Items": [
{
"Name": "Dolly Parton",
"NameId": "dolly-parton",
"Category": "Music",
},
{
"Name": "Cee Lo Green",
"NameId": "cee-lo-green",
"Category": "Music",
},
{
"Name": "Take That",
"NameId": "take-that",
"Category": "Music",
},
{
"Name": "Football",
"NameId": "football",
"Category": "Sport",
},
{
"Name": "Hockey",
"NameId": "hockey",
"Category": "Sport",
}
]
}
I'm looping through all the categories and then printing them into a list while trying to only pass items that relate to that category in an items prop. I have the code below but it is passing all my data to each element and I'm not sure why.
class CategoryItems extends Component {
constructor(props) {
super(props);
}
state = {
items: this.props.items,
categories: this.props.categories,
};
render() {
const items = this.state.items;
return (
<section className="category-wrapper">
<div className="container">
<div className="category-wrapper__inner">
{this.state.categories.map((category, index) => (
<CategoryItem
key={category.Name}
items={items.map((item, index) => {
item.Category === category.Name ? item : '';
})}
/>
))}
</div>
</div>
</section>
);
}
}
All the data is there and in the react dev-tools it says each element has 667 items but I know there should only be 7 items on the sports category.
Apply a filter instead of a map.
<CategoryItem
key={category.Name}
items={items.filter(i => item.Category === category.Name)}
/>
You can try this ,
class CategoryItems extends Component {
constructor(props) {
super(props);
}
state = {
items: this.props.items,
categories: this.props.categories,
};
render() {
const items = this.state.items;
const renderList = this.state.categories.reduce((total, category) => {
const list = items.filter(item => item.Category === category.Name);
if(list.length > 0){
total.push(<CategoryItem
key={category.Name}
items={list}
/>);
}
return total
},[])
return (
<section className="category-wrapper">
<div className="container">
<div className="category-wrapper__inner">
{renderList}
</div>
</div>
</section>
);
}
}