REACT: JSON Tree with the help of Recursion - javascript

The JSON backend guys provide me its multiple parent child so I have to put the dynamic loop to show parent child.
JSON
"data": [
{
"id": 25,
"slug": "mobiles",
"parent_id": null,
"name": "Mobiles"
},
{
"id": 26,
"slug": "mobile-phones-accessories",
"parent_id": 25,
"name": "Mobile Phones accessories"
},
{
"id": 27,
"slug": "computer-laptop",
"parent_id": null,
"name": "Computer & Laptop"
},
{
"id": 28,
"slug": "laptops",
"parent_id": 27,
"name": "Laptops"
},
{
"id": 29,
"slug": "mobile-phones",
"parent_id": 26,
"name": "Mobiles Phone"
}
]
My Function (Kindly ignore this. It's just a try but I have got 1 child parent)
renderCategoriesHtml() {
const { categories } = this.props;
if (!categories) return false;
const nullCat = [];
categories.map((obj) => {
if (obj.parent_id == null) {
nullCat.push(obj);
}
});
return nullCat.map(
(parentCat, i) => (
<div className="form-group" key={i}>
<div className="checkbox" key={i}>
<label>
<Field
name={`categories.${parentCat.id}`}
component="input"
type="checkbox"
/>
{parentCat.slug}
</label>
</div>
{
categories.map(
(childCat, j) => (
parentCat.id == childCat.parent_id ?
<div className="checkbox ml-20" key={j}>
<label>
<Field
name={`categories.${childCat.id}`}
component="input"
type="checkbox"
/>
{childCat.slug}
</label>
</div>
: ''
)
)
}
</div>
)
);
}
I want this (That dynamic html i want)
<ul>
<li>mobiles</li>
<ul>
<li>mobile-phones-accessories</li>
<ul>
<li>mobile-phones</li>
</ul>
</ul>
<li>computer-laptop</li>
<ul>
<li>laptops</li>
</ul>
</ul>

Try this:
class TreeRender extends React.Component {
state = {
data: JSON.parse('[{"id": 25,"slug": "mobiles","parent_id": null,"name": "Mobiles"},{"id": 26,"slug": "mobile-phones-accessories","parent_id": 25,"name": "Mobile Phones accessories"},{"id": 27,"slug": "computer-laptop","parent_id": null,"name": "Computer & Laptop"},{"id": 28,"slug": "laptops","parent_id": 27,"name": "Laptops"},{"id": 29,"slug": "mobile-phones","parent_id": 26,"name": "Mobiles Phone"}]')
}
getCurrent = (node) => this.state.data.filter(cNode => cNode.parent_id == node).map(cNode => (
<ul key={`node_${cNode.id}`}>
<li>{cNode.name}</li>
{this.getCurrent(cNode.id)}
</ul>
))
render() {
return (
<div>
{this.getCurrent(null)}
</div>
);
}
}
FIDDLE

Related

How to update state of dynamic radio input in reactjs?

I am fetching questions using an API and displaying question with dynamic radio options like this
[
{
"id": "question01",
"question": "Which of the following profiles you belongs",
"multiple": false,
"options": [
{
"id": "option01",
"title": "Buyer"
},
{
"id": "option02",
"title": "Planner"
},
{
"id": "option03",
"title": "Merchandiser"
},
{
"id": "option04",
"title": "Designer"
},
{
"id": "option05",
"title": "Analyst"
}
]
},
{
"id": "question02",
"question": "Which of the following is your responsibility?",
"multiple": true,
"options": [
{
"id": "option02_1",
"title": "Planning"
},
{
"id": "option02_2",
"title": "Design"
},
{
"id": "option02_3",
"title": "Development"
},
{
"id": "option02_4",
"title": "Testing"
}
]
},
{
"id": "question03",
"question": "What’s your level of seniority in the organization?",
"multiple": false,
"options": [
{
"id": "option03_1",
"title": "Entry Level"
},
{
"id": "option03_2",
"title": "Mid Level"
},
{
"id": "option03_3",
"title": "Senior Level"
}
]
},
{
"id": "question04",
"question": "Do you work with charts and dashboards to make data-backed decisions? ",
"multiple": false,
"options": [
{
"id": "option04_1",
"title": "Yes"
},
{
"id": "option04_2",
"title": "No"
},
{
"id": "option04_3",
"title": "Others"
}
]
}
]
I am rendering questions with options like this
<div>
{
questions && questions.length > 0 &&
questions.map((question, index) => {
return (
<div key={question.id}>
<div className='row'>
<div className='col-1'>
<h2 className='questionTitle'>Q{index + 1}.</h2>
</div>
<div className='col-11 questionContainer'>
<h2 className='questionTitle'>{question.question}</h2>
</div>
</div>
</div>
<div className='optionsList'>
{
question.options && question.options.map((option, index) => {
return (
<div key={option.id} className="mb-3">
<div className='d-flex align-items-center'>
{
question.multiple ?
<div className="form-check">
<input className="form-check-input form-checkbox" type="checkbox" value={option.title} onChange={() => handleAnswerSelection(option, question.id, true)} id={option.id} />
<label className="form-check-label" htmlFor={option.id}>
{option.title}
</label>
</div>
:
<div className="form-check">
<input className="form-check-input"
type="radio"
name={question.id}
value={option.title}
onChange={() => handleAnswerSelection(option,question.id, false)}
id={option.id}
checked={answersList.length && answersList.filter(ans => ans.id === question.id) && answersList.filter(ans => ans.id === question.id)[0].values[0].title === option.title }
/>
<label className="form-check-label" htmlFor={option.id}>
{option.title}
</label>
</div>
}
</div>
</div>
)
})
}
</div>
and onChange i am handling selection like this
const handleAnswerSelection = (selectedOption, ques, hasMany) => {
if (hasMany) {
//
}
else {
const answer = {
"id": ques,
"values": [selectedOption]
}
if (answersList.length > 0 && answersList.find(ans => ans.id === ques)) {
const index = answersList.findIndex(answer => answer.id === ques);
if (index > -1) {
answersList[index].values = [selectedOption];
}
}
else {
setAnswersList([...answersList, answer]);
}
}
console.log(answersList);
}
but the problem is on changing option is not reflecting at the same time also radio button is not changing.
state variables are
const [answersList, setAnswersList] = useState([]);
please help what i am doing wrong what is the solution for this ? Thanks in advance
const handleAnswerSelection = (selectedOption, ques, hasMany) => {
if (hasMany) {
//
}
else {
const answer = {
"id": ques,
"values": [selectedOption]
}
if (answersList.length > 0 && answersList.find(ans => ans.id === ques)) {
const index = answersList.findIndex(answer => answer.id === ques);
if (index > -1) {
let newAnswersList = [...answersList];
newAnswersList[index].values = [selectedOption];
setAnswersList(newAnswersList);
}
}
else {
setAnswersList([...answersList, answer]);
}
}
console.log(answersList);
}
It will be worked.
You should update answersList value using setAnswersList function.
On the following statement, the answersList value is not changed.
answersList[index].values = [selectedOption];

How to resolve Cross Origin Error In React?

I have made a simple shopping cart using React.js. I am using localStorage to store the state value so that even after the refresh, the values remain in the UI.
Also, does modifying the Items content through states, change the
original Items content?
Following are the different files that I am using to render:
ShoppingCart.js
import React, { Component } from 'react';
import { Table, Button, Media, Card, CardHeader, CardBody, CardFooter } from 'reactstrap';
import Items from '../shared/Items';
class ShoppingCart extends Component {
constructor(props) {
super(props);
this.state = {
items: JSON.parse(localStorage.getItem("items")) || Items
}
}
decreaseQuantity = (item) => {
const copy = this.state.items;
item.quantity -= 1;
for(let i = 0; i < copy.length; i++) {
if(copy[i].id === item.id)
copy[i] = item;
}
localStorage.setItem("items", JSON.stringify(copy));
this.setState({
items: copy
});
};
increaseQuantity = (item) => {
const copy = this.state.items;
item.quantity += 1;
for(let i = 0; i < copy.length; i++) {
if(copy[i].id === item.id)
copy[i] = item;
}
localStorage.setItem("items", JSON.stringify(copy));
this.setState({
items: copy
});
};
resetCart = () => {
localStorage.setItem("items", JSON.stringify(Items));
this.setState({
items: Items
})
};
removeItem = (item) => {
let copy = this.state.items;
copy.splice(copy.indexOf(item), 1);
localStorage.setItem("items", JSON.stringify(copy));
this.setState({
items: copy
});
}
render() {
const array = this.state.items;
const total = array.reduce((acc, item) => acc + item.quantity, 0);
let typeDiscount = 0;
let normalDiscount = 0;
const totalPrice = array.reduce((acc, item) => {
normalDiscount += ((item.quantity * item.price) * item.discount) / 100;
if (item.type === "fiction")
typeDiscount += ((item.quantity * item.price) * 15) / 100;
return acc + (item.quantity * item.price);
}, 0);
const items = array.map((item) => (
<tr key={item.id}>
<td>
<Media>
<Media left className="mr-3">
<Media object data-src={item.img_url} style={{height: 20, width: 20}} placeholder={item.name} />
</Media>
<Media body>
{item.name}
<Button close onClick={() => this.removeItem(item)} />
</Media>
</Media>
</td>
<td>
<Button color="danger" className="mr-3" disabled={item.quantity === 1}
onClick={() => this.decreaseQuantity(item)}>
-
</Button>
{item.quantity}
<Button color="success" className="ml-3" onClick={() => this.increaseQuantity(item)}>+</Button>
</td>
<td>{item.quantity * item.price}</td>
</tr>
));
return (
<React.Fragment>
<div className="container">
<div className="row">
<div className="col-md">
<Table>
<thead>
<tr>
<th>Item({total})</th>
<th>Qty</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{items}
</tbody>
</Table>
</div>
<div className="col-md">
<Card>
<CardHeader>Total</CardHeader>
<CardBody>
<dl className="row p-1">
<dt className="col-6">Items({total})</dt>
<dd className="col-6">{totalPrice}</dd>
<br />
<dt className="col-6">Discount</dt>
<dd className="col-6">{normalDiscount}</dd>
<dt className="col-6">Type Discount</dt>
<dd className="col-6">{typeDiscount}</dd>
</dl>
</CardBody>
<CardFooter>
<dl className="row p-1">
<dt className="col-6">Order Total</dt>
<dd className="col-6">{totalPrice - normalDiscount - typeDiscount}</dd>
</dl>
</CardFooter>
</Card>
</div>
</div>
</div>
<br /><br />
<Button style={{position: "absolute", right: 500}} color="primary" className="mt-5" onClick={this.resetCart}>Reset</Button>
</React.Fragment>
);
}
}
export default ShoppingCart;
App.js
import React from 'react';
import ShoppingCart from './components/ShoppingCart';
function App() {
return (
<div className="mt-5">
<ShoppingCart />
</div>
);
}
export default App;
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import 'bootstrap/dist/css/bootstrap.min.css';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
serviceWorker.unregister();
Items.js
//The JSON file containing the items data
const Items = [{ "id": 9090, "name": "Item1", "price": 200, "discount": 10, "type": "fiction", "img_url": "https://place-hold.it/40.jpg", "quantity": 1 },
{ "id": 9091, "name": "Item2", "price": 250, "discount": 15, "type": "literature", "img_url": "https://place-hold.it/40.jpg", "quantity": 1 },
{ "id": 9092, "name": "Item3", "price": 320, "discount": 5, "type": "literature", "img_url": "https://place-hold.it/40.jpg", "quantity": 1 },
{ "id": 9093, "name": "Item4", "price": 290, "discount": 0, "type": "thriller", "img_url": "https://place-hold.it/40.jpg", "quantity": 1 },
{ "id": 9094, "name": "Item5", "price": 500, "discount": 25, "type": "thriller", "img_url": "https://place-hold.it/40.jpg", "quantity": 1 },
{ "id": 9095, "name": "Item6", "price": 150, "discount": 5, "type": "literature", "img_url": "https://place-hold.it/40.jpg", "quantity": 1 },
{ "id": 9096, "name": "Item7", "price": 700, "discount": 22, "type": "literature", "img_url": "https://place-hold.it/40.jpg", "quantity": 1 },
{ "id": 9097, "name": "Item8", "price": 350, "discount": 18, "type": "fiction", "img_url": "https://place-hold.it/40.jpg", "quantity": 1 }];
export default Items;
I tried running the app, but I kept on getting the following error:
Error: A cross-origin error was thrown. React doesn't have access to the actual error object in development.
Can someone help me with this? What am I doing wrong ?

ReactJs - component nesting to display nested data working abruptly

My data is:
[{
"id": 1,
"label": "List item 1",
"parent_id": 0,
"children": [{
"id": 5,
"label": "List item 1",
"parent_id": 1
},
{
"id": 6,
"label": "List item 1",
"parent_id": 1
},
{
"id": 7,
"label": "List item 1",
"parent_id": 1
},
{
"id": 8,
"label": "List item 1",
"parent_id": 1,
"children": [{
"id": 9,
"label": "List item 1",
"parent_id": 8
},
{
"id": 10,
"label": "List item 1",
"parent_id": 8
}
]
}
]
},
{
"id": 2,
"label": "List item 1",
"parent_id": 0
}
]
My App.js components looks like this:
import React, {useState} from 'react';
import {apiData} from './data/api';
import './App.css';
import {NestedLists} from './components/NestedLists';
const App = () => {
return (
<div className="container">
<h3>Calling a nested component</h3>
<NestedLists filteredData = {data} />
</div>
)
}
export default App;
NestedList component:
import React from 'react'
export const NestedLists = ({filteredData}) => {
return (
<ul>
{filteredData && filteredData.map((m,i) => {
return (
<li key={m.label}>
{m.id}
{m.children && <NestedLists filteredData={m.children} />}
</li>
);
})}
</ul>
)
}
When i check the results there is same nesting printed twice as shown in the below image which should not happen::
Here inside 1: 5,6,7,8 is repeated twice and inside 8 : 9,10 is repeated twice which should not happen. what is missing here?
It is working fine.check where are you making mistake. i have tried this
import React from 'react';
const App = () => {
const data = [{
"id": 1,
"label": "List item 1",
"parent_id": 0,
"children": [{
"id": 5,
"label": "List item 1",
"parent_id": 1
},
{
"id": 6,
"label": "List item 1",
"parent_id": 1
},
{
"id": 7,
"label": "List item 1",
"parent_id": 1
},
{
"id": 8,
"label": "List item 1",
"parent_id": 1,
"children": [{
"id": 9,
"label": "List item 1",
"parent_id": 8
},
{
"id": 10,
"label": "List item 1",
"parent_id": 8
}
]
}
]
},
{
"id": 2,
"label": "List item 1",
"parent_id": 0
}
]
const NestedLists = ({filteredData}) => {
return (
<ul>
{filteredData && filteredData.map((m,i) => {
return (
<li key={m.label}>
{m.id}
{m.children && <NestedLists filteredData={m.children} />}
</li>
);
})}
</ul>
)
}
return (
<div className="container">
<h3>Calling a nested component</h3>
<NestedLists filteredData = {data} />
</div>
)
}
export default App;
I think you are not passing right data here in your App.js file
import {apiData} from './data/api';
<NestedLists filteredData = {data} />
change it to
<NestedLists filteredData = {apiData} />

Displaying data based on json object not working

I am fetching a JSON from a file in one ReactJS component and trying to display it but I don't know why something is not working.
what am I doing wrong?
App.js
import React from 'react';
import Home from './components/Home';
import GameIntro from './components/GameIntro';
import {BrowserRouter,Switch,Route} from 'react-router-dom';
function App() {
return (
<div className='container mt-5 py-5'>
<div className="row">
<div className="col-md-6 offset-md-3">
<BrowserRouter>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/intro' component={GameIntro} />
</Switch>
</BrowserRouter>
</div>
</div>
</div>
)
}
export default App;
JSON file:
gamedata.js
export const gdatas = [
{
"data": [
{
"id": 0,
"image": "https://images.unsplash.com/photo-1492725764893-90b379c2b6e7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "Mom"
},
{
"id": 1,
"image": "https://images.unsplash.com/photo-1482235225574-c37692835cf3?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "Dad"
}
]
},
{
"data": [
{
"id": 2,
"image": "https://images.unsplash.com/photo-1551445523-324a0fdab051?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "Apple"
},
{
"id": 3,
"image": "https://images.unsplash.com/photo-1553279768-865429fa0078?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "Mango"
},
{
"id": 4,
"image": "https://images.unsplash.com/photo-1502741338009-cac2772e18bc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "Blueberry"
}
]
},
{
"data": [
{
"id": 5,
"image": "https://images.unsplash.com/photo-1459411621453-7b03977f4bfc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "broccoli"
},
{
"id": 6,
"image": "https://images.unsplash.com/photo-1531170887152-6b21ba4ce8ae?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "cucumber"
},
{
"id": 7,
"image": "https://images.unsplash.com/photo-1564874997803-e4d589d5fd41?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "tomato"
},
{
"id": 8,
"image": "https://images.unsplash.com/photo-1506807803488-8eafc15316c7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "beetroot"
}
]
},
{
"data": [
{
"id": 9,
"image": "https://images.unsplash.com/photo-1518674660708-0e2c0473e68e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "Pen"
},
{
"id": 10,
"image": "https://images.unsplash.com/photo-1516962215378-7fa2e137ae93?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "Pencil"
},
{
"id": 11,
"image": "https://images.unsplash.com/photo-1541963463532-d68292c34b19?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "Book"
},
{
"id": 12,
"image": "https://images.unsplash.com/photo-1527239441953-caffd968d952?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "Papers"
},
{
"id": 13,
"image": "https://images.unsplash.com/photo-1551818014-7c8ace9c1b5c?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
"word": "Pendrive"
}
]
}
]
the file in which i am trying to display JSON is this:
GameIntro.js
import React from 'react';
import {gdatas} from './gamedata';
const GameIntro = () => {
const gameData = gdatas.map(gd => {
gd.data.map(elm =>(
<div className="card">
<img src={elm.image} className="card-img-top" alt={elm.word} />
<div className="card-body">
<h5 className="card-title mt-3">{elm.word}</h5>
</div>
</div>
))
})
return (
<div className='container'>
<div className="row">
<div className="col-md-6">
{gameData}
</div>
</div>
</div>
)
}
export default GameIntro;
This component GameIntro.js is unable to display JSON.
You are not returning any data from the map function.
Add the return and add a key and you good to go:
const GameIntro = () => {
const gameData = gdatas.map(gd => {
return gd.data.map(elm =>(
<div key={elm.id} className="card">
<img src={elm.image} className="card-img-top" alt={elm.word} />
<div className="card-body">
<h5 className="card-title mt-3">{elm.word}</h5>
</div>
</div>
))
});
return (
<div className='container'>
{gameData}
</div>
)
}

Get initial value from a JSON and add with other values

I'm sweeping a JSON and grabbing the value of a snack.
{
"lanches": [
{
"id": 1,
"name": "X-Bacon",
"ingredients": [
"Bacon",
"Hambúrguer",
"Queijo"
],
"initialValue: 9.00
}
]
}
I need to show it when the system starts .. so far okay.
I have a list of additional items that is another JSON swept.
{
"ingredientes": [
{
"id": 1,
"name": "Alface",
"price": 0.40
},
{
"id": 2,
"name": "Bacon",
"price": 2.00
},
{
"id": 3,
"name": "Hambúrguer de carne",
"price": 3.00
},
{
"id": 4,
"name": "Ovo",
"price": 4.00
},
{
"id": 5,
"name": "Queijo",
"price": 5.00
}
]
}
When you add each item, you need to add up with the initial value. I can add only the added items. I can not add the first value and add it with the items.
Here is where I sweep the JSON to pick up the snacks
{this.state.lanches.map(lanche => (
<div className="item" key={lanche.id}>
<div className="item__desc--top">
<h2 className="item__title">{lanche.name}</h2>
<p className="item__price">{this.state.totalPrice}</p>
</div>
<ul className="item__ingredientes">
{lanche.ingredients.map(ingredientes =>
<li className="item__ingredientes--itens" key={ingredientes}>
<span>{ingredientes}</span>
{ this.state.editItem ? <button className="actionRemove"><i className="fa fa-times"></i></button> : null}
</li>
)}
</ul>
<p className="itens__adicionais">Add Items</p>
<ul className="itens__adicionais--menu">
{this.state.ingredientes.map(ingrediente =>
<li className="itens__adicionais--item" key={ingrediente.id}>
<span>{ingrediente.name}</span>
<button className="actionAdd" onClick={((e) => this.handleAdd(e, ingrediente.price, lanche.price))}><i className="fa fa-plus"></i></button>
</li>
)}
</ul>
</div>
))}
And here is the function of summing the value:
handleAdd = (e, value_ingrediente) => {
this.setState(
{
totalPrice: this.state.totalPrice + value_ingrediente
}
)
}

Categories