How to make 3 column row from API data in React - javascript

First time doing this so please bear with me.
Using Bootstrap. Trying to make some data present itself as a 3 column row. And at the end of each row, make a new row.
Is there a way to do this with the code below?
Code sandbox here.
Here's the code:
<input
className="search"
type="text"
placeholder="Search by model..."
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
/>
{/* Map through first level */}
{data.map((item) => (
<ul>
{/* Filter and map through the second level */}
{item.product_details.filter(filterProducts).map((subItem) => (
<div className="row">
<div className="col-lg-4">
<MachineCard
image={subItem.image}
title={subItem.model}
weight={subItem.operating_weight}
power={subItem.power}
/>
</div>
</div>
))}
</ul>
))}

Related

Hide icon on each last item

I have a nested list with some items
Currently I'm displaying an arrow for each item, which results in a problem - if item has no sub-items, it still shows an arrow.
ListItem code (classNames are excluded for a better reading):
function CodeItem({ props }: CodeItemProps) {
const cpvs = Object.keys(tree) as Array<CpvLabelKey>;
const [open, setOpen] = React.useState(cpvs.some(c => codes.includes(c)));
return (
<div>
<fieldset>
<div >
<button
onClick={() => setOpen(!open)}
aria-expanded={open}
>
// this icon should be displayed only if Item has sub-elements
<UilAngleRight/>
</button>
<input
type="checkbox"
name={`cpv-${code}`}
id={`cpv-${code}`}
checked={checked}
onChange={e => onChange(e.target.checked, code)}
/>
</div>
<label htmlFor={`cpv-${code}`}>
{code} - {tCPV(code)}
</label>
</fieldset>
// where I map each Item
{open && (
<div>
{cpvs.map(code => (
<CodeItem
key={code}
code={code}
onChange={onChange}
tree={tree[code]?.children || {}}
checked={codes.includes(code)}
codes={codes}
/>
))}
</div>
)}
</div>
);
}
How could I hide arrow on last elements, which has no over sub-elements?
You can check if the array is not empty before rendering the icon
{!!cpvs.length && <UilAngleRight/>}

How can I focus the cursor to the next TextInput in a React Draggable Menu?

I have a draggable context menu with three rows and three TextInputs. Right now I have two bugs:
When "tab" is hit, the menu closes
Even when I stop "tab" from closing (I return in the handleClose), "tab" doesn't focus the cursor to the next TextInput.
I've tried adding tabIndex={0} to the three divs that surround each TextInput, but this didn't help with the tab issue.
Does anyone know what might be wrong here?
Below is the simplified code (variables such as startNumber, endNumber, comments are state variables).
const handleClose = (event?, reason?) => {
if (reason && reason === 'tabKeyDown') {
// Prevent the 'Tab' key from closing the window
return;
}
setShouldOpen(false);
otherStuffHere();
}
...
return (
<Draggable cancel="textarea">
<Menu
open={shouldOpen}
onClose={handleClose}
anchorReference="anchorPosition"
anchorPosition={{ top: y, left: x }}
className={classes.myContextMenu}
>
<div className={classes.row}>
<div className={classes.title}>
<Text>First number</Text>
</div>
<div className={classes.text} tabIndex={0}>
<TextInput
fullWidth
value={startNumber}
disabled={readOnly}
onChange={handleStartNumberChange}
/>
</div>
</div>
<div className={classes.row}>
<div className={classes.title}>
<Text>End number</Text>
</div>
<div className={classes.text} tabIndex={0}>
<TextInput
fullWidth
value={endNumber}
disabled={readOnly}
onChange={handleEndNumberChange}
/>
</div>
</div>
<div className={classes.row}>
<div className={classes.title}>
<Text>Comments</Text>
</div>
<div className={classes.text} tabIndex={0}>
<TextInput
fullWidth
value={comments}
disabled={readOnly}
onChange={handleCommentsChange}
/>
</div>
</div>
</Menu>
</Draggable>
)
I wasn't able to find a solution while still using the Menu component, but I used the Popover component instead.
Using the same CSS and same everything else, I got the tab to work as intended without changing the UI.

Handle an aray of inputs in react

Im trying to handle an aray of inputs in react which are viewed by ".map" function.
The problem is I couldn't give the field a specific value. As a result i couldn't handle the input in onChange function.
I have list of card each card will have a Admin description input and two buttons each one will send a different request.
Here A made the function that present the cards. The porplem is with the input
function createrequestcard(prop){
return(
<Card className="text-center" key={prop._id}>
<div class="wrapper">
<div id="requestspart1" class="left">
<Card.Body>
<Card.Title>Admin Description</Card.Title>
<Card.Text>
<textarea
// --> Value of the index in aray
// --> Handle Change of input
/>
</Card.Text>
</Card.Body>
</div>
<div id="requestspart3" class="left">
<Card.Body>
<Card.Title>CREATE</Card.Title>
<Button variant="outline-success" className="AdminRequestButton">APPROVE</Button>
<Button variant="outline-danger" className="AdminRequestButton">DENY</Button>
</Card.Body>
</div>
</div>
</Card>
)
}
In initialising values on class
this.state = {
requests: [],
description: '',
}
}
The request aray is updated from the backend:
componentDidMount(){
this.checkloginstatus();
axios.get('http://localhost:3000/request', {withCredentials: true})
.then(resp => {
this.setState({requests: resp.data})
}).catch(err => console.log(err))
}
And in render function:
<div>
{this.state.requests.map(createrequestcard)}
</div>
Thank you very much for helping me out.
You can pass index in map method like the below,
<div>
{this.state.requests.map((req,index) => createrequestcard(req, inex))}
</div>
function createrequestcard(prop, index){
The structure of map method is like below
map((element) => { ... } )
map((element, index) => { ... } )
map((element, index, array) => { ... } )
your card component should defined as follow, here i have named it RequestCard (just to make more readable),
this component will get handleOnChange as argument , we will pass updated value to it,when onchange event occurs in
textarea.
function RequestCard(props){
return(
<Card className="text-center" key={prop._id}>
<div class="wrapper">
<div id={props.id} class="left">
<Card.Body>
<Card.Title>Admin Description</Card.Title>
<Card.Text>
<textarea
onChange={(e)=>props.handleOnChange(e.target.value)}
// --> Value of the index in aray
// --> Handle Change of input
/>
</Card.Text>
</Card.Body>
</div>
<div id="requestspart3" class="left">
<Card.Body>
<Card.Title>CREATE</Card.Title>
<Button variant="outline-success" className="AdminRequestButton">APPROVE</Button>
<Button variant="outline-danger" className="AdminRequestButton">DENY</Button>
</Card.Body>
</div>
</div>
</Card>
)}
now you should render it as follow
<div>
{this.state.requests.map((request,index)=>{
return <RequestCard id={index} handleOnChange={(updatedValue)=>this.handleOnChange(index,updatedValue)}
})}
finally your handleOnChange of parent component should be like this,
handleOnChange=(index,updatedValue)=>{
let curState=this.state;
curState.requests[index].value=updatedValue;//note that i am not aware what member of request you want to update
//so i assume value is the member of request object,you can change whatever you want
this.setState(curState);
}

How to add classes to dynamically created elements in React JS?

{temp_array_beg.map((el,index) => (
<div key={index} className="subRenderButton">
<input type="button" value={el.i} className="paginationBtn" onClick= {this.handlePaginationClick.bind(this)} />
</div>
))}
Ihave tried Conditional Rendering of class but then all the rendered divs got the active class
{temp_array.map((btn,index) => (
<div key={index} className="subRenderButton">
<input type="button"value={btn.i} className={["paginationBtn",buttonNumber == btn.i ? "active" :""].join(' ')} onClick={this.handlePaginationClick.bind(this)} />
</div>
))}
I have managed to solve the problem Thanks!

How can I style map items to display in justify-content-around?

I'm looping through products by mapping them and the justify-content-around doesn't apply to them and I'm using bootstrap 4 in my react project .
Here is my code :
{props.products.map((item) => {
if (item.inCart) {
return (
<div className="d-flex justify-content-around w-100" key={item.id}>
<button>remove</button>
<div>
<h5>{item.name}</h5>
</div>
<div>
<h5>{item.price.toLocaleString('ar-EG')}</h5>
</div>
<div>
<h5>{item.number.toLocaleString('ar-EG')}</h5>
</div>
<div>
<h5>{(item.number * item.price).toLocaleString('ar-EG')}</h5>
</div>
<hr />
</div>
);
}
The display flex class applies but not the other one and they all have no margin between them .
How can I make them to display justify-content-around ??
Your problem come from the <hr> tag. I just discovered it by doing this repro on stackblitz. Remove it and it works.
If you readlly need it then just receate it:
const Divider = () => {
return <div className="border-bottom" />;
};
This one is bootstrap dependant but of course you can make it generic easily. You just need to apply it outside of your flex container :
<>
<div className='d-flex justify-content-around' key={item.id}>
<button>remove</button>
<h5>{item.name}</h5>
<h5>{item.name}</h5>
<h5>{item.name}</h5>
</div>
<Divider />
</>;

Categories