Map with bootstrap columns - javascript

I'm using map to iterate throug a list of elements, what I want is to have 4 elements per row. This is my render part of the class:
render() {
return (
<div>
<h1>Card List</h1>
{this.props.items ? this.props.items.map((item) =>
<div class="cardSection">
<Row className="show-grid">
<Card name={item.name} imgGold={item.imgGold} />
</Row>
</div>
) : <div>Loading!</div>}
</div>
)
}
}
I want 4 Card components per row using xs={4} md={4}

You can do something like
const items = [
{ name: "1" },
{ name: "2" },
{ name: "3" },
{ name: "4" },
{ name: "5" },
{ name: "6" },
{ name: "7" },
{ name: "8" },
{ name: "9" },
{ name: "10" },
{ name: "11" },
];
const App = () => {
const result = items.map((x,i) => {
return i % 4 === 0 ? items.slice(i, i+4) : null;
}).filter(x => x != null);
return (
<div>
{result.map((result, index) => {
return (<section key={index}>
{result.map(item => <span>{item.name}</span>)}
</section>);
})}
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
span {
margin-left: 5px;
margin-right: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
This will group your item array into groups of 4. You can even make it accept any number you want.
You can then iterate and render each of them in groups of 4.
Please make sure you run the snippet so you can see it working.

Related

How to iterate json object field in react

There is a JSON for categories with the following structure
[
{
"category": "Mobiles",
"sub": [
{
"name": "Apple"
},
{
"name": "Samsung"
}
]
},
{
"category": "Televisions",
"sub": [
{
"name": "Lg"
},
{
"name": "Sony"
}
]
}
]
First i load data from backend to a variable called categories (On the backend side im using expressjs and pass data with res.json(JSON.parse(fs.readFileSync('categories.json')))
I want to iterate through categories sub category with
{categories.map(function (category, i) {
return (
<>
<h6 Key={i}>{category.category}</h6> //For example: <h6>Mobiles</h6>
<>... [logic to iterate the current category's sub categories] ...</> //For example: <p>Apple</p> <p>Samsung</p>
</>
);
})}
I tried to use a second map on category.sub like category.sub.map((s,j)=><p Key={j}>{s.name}</p>) but unfortunely i can't get it work, and I can't describe my problem to Google in English so it can be an easy answer and i am the big L
Any help?
Thanks
Try this, uncomment out the console.log to verify data if screen is white.
return (
<>
{categories.map(function (category, i) {
// console.log(category.category );
// console.log(category.sub );
return (
<>
<h6 key={i}>{category.category}</h6>
<>
{category.sub.map(function (sub, j) {
// console.log(category.category + '' + sub.name);
return <p key={j}> {sub.name}</p>;
})}
</>
</>
);
})}
</>
);
Data:
let categories = [
{
category: 'Mobiles',
sub: [
{
name: 'Apple',
},
{
name: 'Samsung',
},
],
},
{
category: 'Televisions',
sub: [
{
name: 'Lg',
},
{
name: 'Sony',
},
],
},
];

How can I create a menu with my json info with REACT

what I try to do is to have the same display as this picture :
So in my menu the plant type (Type of plant1) is displayed above a gray bar and when you click on the down chevron then you can see all the plants name, related to this type, with checkboxes on left, by default there will be all checked. And the blue rectangle indicates the number of plants that have been selected.
How can I do that, which package can help me in REACT?
Here my plants.json :
{
"plants_type": [
{
"_id_type": "1",
"name_type": "Type of plant1",
"plants": [
{
"name": "Plant1.1",
"_id": "2"
},
{
"name": "Plant1.2",
"_id": "3"
}
]
},
{
"_id_type": "4",
"name_type": "Type of plant2",
"plants": [
{
"name": "Plant2.1",
"_id": "5"
},
{
"name": "Plant2.2",
"_id": "6"
}
]
}
]
}
You can create a dropdown list on your own like below. I have added the logic of selecting items to the data itself.
You can keep a component called Category to keep a single state of the parent menu item. Whether it's open or not. Then iterate over the plants as checkbox inputs to make them selectable.
I have used a simple initialize function to make all the items selected initially. This should work as you expect. Add a console log of selectionMenu to see how selected property changes while toggling items.
Move the inline styles to CSS classes to make the code more clear.
const data = { plants_type: [ { _id_type: "1", name_type: "Type of plant1", plants: [ { name: "Plant1.1", _id: "2" }, { name: "Plant1.2", _id: "3" } ] }, { _id_type: "4", name_type: "Type of plant2", plants: [ { name: "Plant2.1", _id: "5" }, { name: "Plant2.2", _id: "6" } ] } ] };
const Category = ({ _id_type, name_type, plants, changeSelection }) => {
const [toggleState, setToggleState] = React.useState(false);
return (
<div key={_id_type}>
<div
style={{
cursor: "pointer",
userSelect: "none",
display: "flex",
margin: "2px",
backgroundColor: "lightgray"
}}
onClick={() => setToggleState((prev) => !prev)}
>
<div>{name_type}</div>
<div
style={{
backgroundColor: "blue",
color: "white",
padding: "0px 10px",
marginLeft: "auto"
}}
>
{plants.filter(({ selected }) => selected).length}
</div>
</div>
<div style={{ marginLeft: "10px" }}>
{toggleState &&
plants.map(({ name, _id, selected }) => (
<div key={_id}>
<input
key={_id}
type="checkbox"
value={name}
checked={selected}
onChange={(e) => changeSelection(_id_type, _id, e.target.value)}
/>
{name}
</div>
))}
</div>
</div>
);
};
const App = () => {
const initializeSelectionMenu = (data) => {
return data.map((item) => {
return {
...item,
plants: item.plants.map((plant) => ({ ...plant, selected: true }))
};
});
};
const [selectionMenu, setSelectionMenu] = React.useState(
initializeSelectionMenu(data.plants_type)
);
console.log(selectionMenu);
const changeSelection = (catId, itemId, value) => {
setSelectionMenu((prevSelectionMenu) =>
prevSelectionMenu.map((item) => {
if (item._id_type === catId) {
return {
...item,
plants: item.plants.map((plant) => {
if (plant._id === itemId) {
return { ...plant, selected: !plant.selected };
}
return plant;
})
};
}
return item;
})
);
};
return (
<div>
{selectionMenu.map((item) => (
<Category
{...item}
changeSelection={changeSelection}
key={item._id_type}
/>
))}
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>

Iterate over JS object of arrays

I have this object that I'm trying to loop over in a form but really can't get it to work. Here is sample of the object.
const data = {
"Social Security": [
{
label: "Deduction Type",
value: "Social Security",
name: "SocialSecurity"
},
{
label: "Employer Rate",
value: "12.4%",
name: "SocialEmployer"
},
{
label: "Employee Rate",
value: "6.2%",
name: "SocialEmployee"
}
],
"Medicare": [
{
label: "Deduction Type",
value: "Medicare",
name: "Medicare"
},
{
label: "Employer Rate",
value: "1.45%",
name: "MedicareEmployer"
},
{
label: "Employee Rate",
value: "2.9%",
name: "MedicareEmployee"
}
]
}
form implementation
<Formik>
{({ values, isSubmitting, resetForm, setFieldValue }) => (
<Form id="payrollSettingsForm" >
<Grid container className={classes.border}>
<Grid item xs={12} md={4}>
{Object.entries(data).map(arr =>{
Array.isArray(arr) && arr.map(elm =>{
return (<TextField
label={elm.label}
value={elm.value}
name={elm.name}
/>)
})
})}
</Grid>
</Grid>
...rest of the form
</Form>
</Formik>
Tried many approaches like Object.fromEntries(). forEach I think all the methods I can find example and keep failing, maybe I'm doing something wrong, any help will be appreciated.
{Object.entries(data).map(([key, val]) =>{
return val.map(elm =>{
return (
<TextField
label={elm.label}
value={elm.value}
name={elm.name}
/>
)
})
})}
Map should return an element on each iteration. In case you don't want to display return null else return a react node.
<Grid item xs={12} md={4}>
{Object.entries(data).map(arr => {
Array.isArray(arr) ? arr.map(elm => {
return (<TextField
label={elm.label}
value={elm.value}
name={elm.name}
/>)
}) : null
})}
</Grid>

Is it possible to pass variable to antD Statistics component in React?

I'm trying to render data from a variable / function into an antD Statistic Component. It appears it can only take a raw string or number, but I need to pass data from props into it.
Is there a way around this? See code below - I would like to pass scenarios[0].investment into "Statistic title="Investment" value={scenarios[0].investment}" but it doesn't allow it. Current code below works AS-IS but breaks when I replace it with scenarios[0].investment
class RenderSummary extends Component {
state = {
clicked: false,
hovered: false,
};
hide = () => {
this.setState({
clicked: false,
hovered: false,
});
};
handleHoverChange = visible => {
this.setState({
hovered: visible,
clicked: false,
});
};
handleClickChange = visible => {
this.setState({
clicked: visible,
hovered: false,
});
};
render() {
const scenarios = this.props.scenarios;
const data = [
{
title: 'Title 1', content: <Statistic title="Investment" value={0}/>,
},
{
title: 'Title 2', content: <Statistic title="T Savings" value={0}/>,
},
{
title: 'Title 2', content: <Statistic title="E Savings" value={0}/>,
},
];
const hoverContent = <div>This is hover content.</div>;
const clickContent = <div>This is click content.</div>;
const onClick = () => console.log("Works!");
return(
<div className="container">
<div className="site-card-wrapper">
<Row gutter={16}>
<Col span={12}>
<Card title="User Scenario 1" bordered={true}>
<List
grid={{ gutter: 16, column: 3 }}
dataSource={data}
renderItem={item => (
<List.Item>
{item.content}
</List.Item>
)}
/>
</Card>
</Col>
</Row>
</div>
</div>
);
}
}
scenarios in props as follows
"scenarios : [0: {id: 0, investment: 0, tSavings: 0, eSavings: 0 …},1: {id: 0, investment: 1, tSavings: 1, eSavings: 1 …}]"
I think the way you have structured your scenarios array or the way you are passing it is incorrect.
An example of how you could pass scenarios to RenderSummary:
const App = () => {
const scenarios = [
{investment: 1}, // Add your other properties
{investment: 2},
{investment: 3},
]
return <RenderSummary scenarios={scenarios}/>
}
If you pass scenarios like above, you can pass it in the way you wanted to:
const data = [
{
title: "Title 1",
content: <Statistic title="Investment" value={scenarios[0].investment} />,
},
{
title: "Title 2",
content: <Statistic title="T Savings" value={scenarios[1].investment} />,
},
{
title: "Title 2",
content: <Statistic title="E Savings" value={scenarios[2].investment} />,
},
];

React, show quantity of how many elements match after filtering

I have this input that filters through a state and shows only the elements that match after typing something, as an extra bonus I need to show the quantity of how many items match.
For example:
If I type "react" only the elements with the react word in it will be shown so the render should show something like this.
There are 2 enterprises that have what you need
My code:
const searchingFor = (term) => {
return (x) => {
return x.tecnologia.toLowerCase().includes(term.toLowerCase()) || !term;
}
}
class FilterClass extends React.Component {
constructor(props) {
super(props);
this.state = {
empresas: [
{
empresa: "Daniel",
tecnologia: "React",
clientes: ["sodimac", "ripley", "paris"],
experiencia: "5 años",
id: 1
},
{
empresa: "Juan",
tecnologia: "React",
clientes: ["Falabella", "ripley", "ikea"],
experiencia: "3 años",
id: 2
},
{
empresa: "David",
tecnologia: "Angular",
clientes: ["Falabella", "ripley", "ikea"],
experiencia: "3 años",
id: 2
},
{
empresa: "Carlos",
tecnologia: "Vue",
clientes: ["Copec", "Wallmark", "Unimark"],
experiencia: "6 años",
id: 3
}
],
term: ''
}
this.searchHandler = this.searchHandler.bind(this);
}
searchHandler(event) {
this.setState({ term: event.target.value })
}
render() {
const {term, empresas} = this.state;
return (
<div>
<form className="container--flex-center">
<input type="text" onChange={this.searchHandler} value={term} />
</form>
{empresas.filter(searchingFor(term)).map(item =>
<FilterComponent
empresa={item.empresa}
tecnologia={item.tecnologia}
clientes={item.clientes}
experiencia={item.experiencia}
key={item.id}
/>
)}
</div>
)
}
}
export default FilterClass;
Well, I do not know where this bonus message should appear, so excuse me if it is not the correct answer.
Well I inserted the message just below the map and then put a filter in the matrix that returns the size as a condition to render the bonus message.
{empresas.filter(element => element.tecnologia === term).length > 0 &&
<div>
here are {empresas.filter(element => element.tecnologia === term).length} enterprises that have what you need
</div>
}
Result
render() {
const {term, empresas} = this.state;
return (
<div>
<form className="container--flex-center">
<input type="text" onChange={this.searchHandler} value={term} />
</form>
{empresas.filter(element => element.tecnologia === term).map(item =>
<FilterComponent
empresa={item.empresa}
tecnologia={item.tecnologia}
clientes={item.clientes}
experiencia={item.experiencia}
key={item.id}
/>
)}
{empresas.filter(element => element.tecnologia === term).length > 0 &&
<div>There are {empresas.filter(element => element.tecnologia === term).length} enterprises that have what you need</div>
}
</div>
)
}
If you want to pass the count of the matched results you can do a trick like this. First Filter you empresas array with your condition then map it.
import React, { Component } from "react";
const searchingFor = term => {
return x => {
return x.tecnologia.toLowerCase().includes(term.toLowerCase()) || !term;
};
};
class FilterClass extends React.Component {
constructor(props) {
super(props);
this.state = {
empresas: [
{
empresa: "Daniel",
tecnologia: "React",
clientes: ["sodimac", "ripley", "paris"],
experiencia: "5 años",
id: 1
},
{
empresa: "Juan",
tecnologia: "React",
clientes: ["Falabella", "ripley", "ikea"],
experiencia: "3 años",
id: 2
},
{
empresa: "David",
tecnologia: "Angular",
clientes: ["Falabella", "ripley", "ikea"],
experiencia: "3 años",
id: 3
},
{
empresa: "Carlos",
tecnologia: "Vue",
clientes: ["Copec", "Wallmark", "Unimark"],
experiencia: "6 años",
id: 4
}
],
term: "",
matchedcount: 0
};
this.searchHandler = this.searchHandler.bind(this);
this.contnmap = this.contnmap.bind(this);
}
searchHandler(event) {
this.setState({ term: event.target.value });
}
contnmap(term, empresas) {
let matchedcount = empresas.filter(searchingFor(term));
let count = Object.keys(matchedcount).length;
return [
matchedcount.map(item => (
<FilterComponent
empresa={item.empresa}
tecnologia={item.tecnologia}
clientes={item.clientes}
experiencia={item.experiencia}
key={item.id}
/>
)),
count
];
}
render() {
const { term, empresas } = this.state;
return (
<div>
<input type="text" onChange={this.searchHandler} value={term} />
{this.contnmap(term, empresas)[0]}
<div>count:{this.contnmap(term, empresas)[1]}</div>
</div>
);
}
}
export default FilterClass;
Here the contnmap() function returns an array where the 1st element will be the set of react elements and the next is the count.
You can just save the result of the filter (and render them later) and use .length to get the count:
render() {
const {term, empresas} = this.state;
const termItems = empresas.filter(searchingFor(term))
return (
<div>
<form className="container--flex-center">
<input type="text" onChange={this.searchHandler} value={term} />
</form>
<p>There are {termItems.length} enterprises that have what you need</p>
{termItems.map(item =>
<FilterComponent
empresa={item.empresa}
tecnologia={item.tecnologia}
clientes={item.clientes}
experiencia={item.experiencia}
key={item.id}
/>
)}
</div>
)
}
This way, you don't have to filter twice and just use a variable. Simple, clean, and reusable.

Categories