Hide icon on each last item - javascript

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/>}

Related

How to pass selected items data to another component React

I have a Menu component, which displays my Menu items. I also have here function addToCart and Cart icon. Function addToCart works fine and store array of selected items.
const Menu = () => {
const [cart, setCart] = useState([]);
const addToCart = (el) => setCart( [...cart, el]);
console.log(cart);
return (
<>
<Tabs className="tabs-wrapper" id="menu">
<TabList className="tabs">
<Tab className="tab-item">Burgers</Tab>
<Tab className="tab-item">Lunch of the day</Tab>
<Tab className="tab-item">Crepes</Tab>
</TabList>
<TabPanel>
<div className="burgers">
<ul>
{burgers.map(burger => (
<li key={burger.id}>
<h4>{burger.title}</h4>
<span>{burger.price}</span>
<img src={burger.image} alt={burger.title} />
<p>{burger.description}</p>
<button type="submit" onClick={() => addToCart(burger.title, "burger")}>Add to cart</button>
</li>
))}
</ul>
</div>
</TabPanel>
<TabPanel>
<div className="crepes">
<ul>
{crepes.map(crepe => (
<li key={crepe.id}>
<h4>{crepe.title}</h4>
<span>{crepe.price}</span>
<img src={crepe.image} alt={crepe.title} />
<p>{crepe.description}</p>
<button type="submit" onClick={() => addToCart(crepe.title, "crepe")}>Add to cart</button>
</li>
))}
</ul>
</div>
</TabPanel>
</Tabs>
<FontAwesomeIcon className="cart" icon={["fas", "shopping-cart"]}/>
</>
)
}
How to pass these items info to Cart component, which I want to open on Cart icon click? Also I would like to avoid router if it's possible.
Edit:
How to make Cart component show image,title and price properties of items, added to a Cart?
const Cart = (props) => {
return (
<>
<div>
<img src={props.image} alt={props.title} />
<h4>{props.title}</h4>
<span>{props.price}</span>
</div>
<Form/>
</>
)
}
You can pass cart with other props to CartComponent.
<CartComponent cart={ cart }/>
If your CartCompoennt is outside menu you should bring your cart state up in that way to by able pass them where you need.
function App() {
const [cart, setCart] = useState([]);
const addToCart = (el) => setCart( [...cart, el]);
return (
<div>
<CartComponent cart={ cart }/>
<Menu cart={ cart } addToCart={ addToCart } />
</div>
)
}

How to pass data from a table row and pass it to another component when it renders?

I have a component that shows a table and one of its columns have a field Actions which has buttons (view, edit, delete etc.). On button click, I need to render another component (component is a popup) and pass the data from the table so that it displays the data in some form which I need to further add.
I have managed to get the current data from its row by passing in onClick. I tried to use state for another component to render but it didn't work out. I'm using Semantic-UI React components to display the button with animations.
Here is the code that has the table,
const MainContent = () => {
const [actions, setActions] = useState(false);
const handleView = (rowData) => {
console.log(rowData);
setActions(true);
if (actions == true) return <ParentView />;
};
....
....
const contents = (item, index) => {
return item.routeChildEntry ? (
<>
<tr key={index}>
<td>{item.appName}</td>
<td></td>
<td>{item.createdTs}</td>
<td>{item.pattern}</td>
<td></td>
<td></td>
<td></td>
<td>
<Button animated onClick={() => handleView(item)}>
<Button.Content visible>View</Button.Content>
<Button.Content hidden>
<Icon name="eye" />
</Button.Content>
</Button>
</td>
</tr>
{item.routeChildEntry.map(routeContents)}
</>
) : (
....
....
....
);
};
return (
<div>
....
{loading ? (
<div className="table-responsive">
<table className="table">
<thead>
<tr>
<th>AppName</th>
<th>Parent_App</th>
<th>Created_Date</th>
<th>Req_Path</th>
<th>Resp_Code</th>
<th>Resp_Content_Type</th>
<th>Resp_Delay</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{data.map((routes, index) => {
return routes.map(contents, index);
})}
</tbody>
</table>
</div>
) : (
....
....
)}
</form>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default MainContent;
Below is the component to render on button click,
import React from "react";
import Popup from "reactjs-popup";
import { Icon } from "semantic-ui-react";
const Parent = (props) => {
return (
<Popup trigger={<Icon link name="eye" />} modal closeOnDocumentClick>
<h4>in parent</h4>
</Popup>
);
};
export default Parent;
How can I render the other component and pass data to it on button click?
Data can be passed to other components as props.
For example, if your component is <ParentView />, and the data you are passing is contained in the variable rowData, you can pass it as:
<ParentView dataPassedByAkhil = {rowData}/>
Then in your ParentView component,
export default function ParentView({dataPassedByAkhil}) {
console.log(dataPassedByAkhil);
Alternatively, you can accept the data as props as below
export default function ParentView(props) {
console.log(props.dataPassedByAkhil);
If you want to open and close another popup, you can pass a state just like above.
<PopupComponent open={stateSetForPopupByParent}/>
Example of popup using state.
Updated link above with how to pass data to the dialog from rows of buttons
Here is the full code:
export default function FormDialog() {
const [open, setOpen] = React.useState(false);
const [valueofRow, setValueOfRow] = React.useState();
const handleClickOpen = (value) => {
setValueOfRow(value);
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
<Button
variant="outlined"
color="primary"
onClick={() => {
handleClickOpen("John");
}}
>
Row 1 - value is John
</Button>
<br />
<br />
<Button
variant="outlined"
color="primary"
onClick={() => {
handleClickOpen("Sally");
}}
>
Row 2 Value is Sally
</Button>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="edit-apartment"
>
<DialogTitle id="edit-apartment">Edit</DialogTitle>
<DialogContent>
<DialogContentText>Dialog fired using state</DialogContentText>
<h1>{valueofRow} was clicked and passed from the row</h1>
<TextField
autoFocus
margin="dense"
id="field"
label="some field"
type="text"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="secondary">
Cancel
</Button>
<Button onClick={handleClose} color="primary">
Submit
</Button>
</DialogActions>
</Dialog>
</div>
);
}

Can I filter elements based on searchbox input in React?

I'm incredibly new to react and web development in general and I wanted to start by making a very simple shopping cart app. I found a nice tutorial on youtube for it, and am now trying to expand on it a bit. I wanted to add a search bar that filters out elements on the home-page as you type in it.
const Home = (props) => {
function handleChange(e){
console.log(e.target.value);
}
return (
<div>
<Row align="middle" className='title'> **search bar**
<Input placeholder="Search for a school" onChange={handleChange} />
</Row>
<Row align="middle" className='title'>
<Divider orientation="left"><b>Category E Schools</b></Divider>
</Row>
<Row align="middle" className='container'>
**Every item for sale is in a Col element**
<Col className = "Princeton University" xs={0} md={11} align="left">
<div className='image'>
<img src={Princeton} alt="Princeton University" />
<h3>Princeton</h3>
<h3>$1100.00</h3>
<button onClick={() => props.addBasket('princeton')} className='addToCart cart1' href='#'>Add to Cart</button>
</div>
</Col>
I'm using AntDesign Row-Col components, and my thought was to define a className for each Col. I was hoping that with the className I could implement the handleChange function to directly remove elements whose classNames don't contain the letters typed into the input bar. Sorry for the beginner-level work going on here.
Pat of the genius of react is that you can abstract your components and render them dynamically. to do this I would create a reusable component for all items and then render them dynamically.
Example:
first create an item component
const Item = (props) => (
<Col className = "Princeton University" xs={0} md={11} align="left">
<div className='image'>
<img src={props.image} alt={props.title} />
<h3>{props.title}</h3>
<h3>{props.cost}</h3>
<button onClick={() => props.addBasket('princeton')} className='addToCart cart1' href='#'>Add to Cart</button>
</div>
</Col>
)
}
add your items to state and render your state dynamically
also here I added state to search and set up two way binding between my input and my state value
i also added the filter method to my dynamic rendering of the items
i would recommend adding a library like loadash and using the debounce function so that the results re-render once 350ms after the user finishes typing instead of re-rendering on every single keystroke from the user
const Home = (props) => {
const [items, setItems] = useState([
{name: Princeton, price: 140000.00, img: http:princetonimages.com/f313b},
])
const [search, setSearch] = useState('')
const renderItems = (items) => (items.map(item => <Item {...item} />))
return (
<div>
<Row align="middle" className='title'> **search bar**
<Input
placeholder="Search for a school"
onChange={(e) => setSearch(e.target.value)}
value={search}
/>
</Row>
<Row align="middle" className='title'>
<Divider orientation="left"><b>Category E Schools</b></Divider>
</Row>
<Row align="middle" className='container'>
{renderItems(state.items.filter(search))}
</Row>
)
}

Modal not selecting current object

I have this class in React:
render() {
let addedItems = this.props.items.length ? (
this.props.items.map(item => {
return (
<li className="collection-item avatar" key={item.id}>
<div className="item-desc">
<Modal trigger={<Button onClick={this.handleOpen}>Editar</Button>}>
<Header icon="archive" content="Archive Old Messages" />
<Modal.Content>
{/* CHEESE */}
<Button.Group>
<Link to="/cart">
<Button
icon="plus"
onClick={() => {
console.log("BUT +");
this.handleCheese(item, "+");
}}
/>
</Link>
<Button content="Cheese" labelPosition="left" />
<Link to="/cart">
<Button
icon="minus"
onClick={() => {
this.handleCheese(item, "-");
}}
/>
</Link>
<h2>{item.queijo}</h2>
</Button.Group>
</Modal.Content>
</Modal>
</div>
</li>
);
})
)
}
In resume a modal should open according to the object I'm selecting.
But in my code the item.id is selecting the last object I inserted in the addedItems.
I need the modal to have the info about the obj I selected.
In case you want to see all code is in: https://github.com/fernanda-avelar/burguer_cart ->
This page is the /src/components/Cart.js
I guess you can have only one modal in your window, that's why it's taking the last one (by having overriden all others).
So instead you should put your modal out of the .map.
Also, keep track of the selected item via a controlled state selectedItem.
Then use it the the Modal.Content :
render() {
return (
<>
<Modal.Content>
/* content depending of this.state.selectedItem */
</Model.Content>
/* your other stuff */
</>
)
}

React mouseEnter event not working when on mapped children

I just want these child elements to show a remove button on mouseover...
console logging in handleMouseEnter shows that on render, ALL children fire the mouseEnter event. it seems stuck in a loop. debugging is next to impossible.
problems only arise when onMouseEnter and onMouseLeave are left in the code.
render(){
const handleMouseEnter = (tool) => this.setState({display : tool});
const handleMouseLeave = () => this.setState({display : "none"});
return (
<div>
<div className="search-result-background">
<div className="search-result-row row">
<div className="col-md-4">
</div>
<div className="col-md-4">
<form>
<TextFieldGroup className="find-tool-search-bar"
onChange= {this.checkToolExists}
value = {this.state.toolname}
field = 'toolname'
label = ''
error = {this.state.errors}
placeholder = "FIND IN FAVORITES"
/>
</form>
</div>
<div className="col-md-4">
<ButtonToolbar>
<DropdownButton noCaret onSelect={this.sort} bsSize="large" title="Sort by" id="dropdown-size-large">
<MenuItem eventKey="1">Name</MenuItem>
<MenuItem eventKey="2">Uploaded Date</MenuItem>
</DropdownButton>
</ButtonToolbar>
</div>
<h1 className="search-error">{this.state.errors}</h1>
<div className="col-md-12" >
{this.state.filteredTools.map((tool,i)=>
<div key ={i} className={"child " + tool.toolname } onMouseEnter={handleMouseEnter(tool.toolname)}
onMouseLeave={handleMouseLeave}> {this.state.display == tool.toolname ?
<button >remove?</button> : null}
<Link to={`/tools/${tool.id.substring(4)}`}>
<Thumbnail
className="thumb" src={logoImagePurple} alt="242x200">
<h3>{tool.toolname}</h3>
</Thumbnail>
</Link>
</div>
)}
</div>
</div>
</div>
</div>
)
}
}
The problem is this line:
onMouseEnter={handleMouseEnter(tool.toolname)}
You should change it to:
onMouseEnter={() => handleMouseEnter(tool.toolname)}

Categories