See element onHover in mapped list with react - javascript

I have a list I want an x icon to appear when user hovers over the item. Currently when user hovers over 1 item the x icon appears on all items in the list. How can I identify just 1 element from the list?
component
const [delWatchlist, setDelWatchlist] = useState(false);
<UncontrolledDropdown isOpen={dropdownOpen} toggle={toggle} className="watchlist-dropdown">
<DropdownToggle caret>
{selected}
</DropdownToggle>
<DropdownMenu>
<DropdownItem onClick={() => createForm()}>Create new list</DropdownItem>
<DropdownItem onClick={() => renameForm()}>Rename</DropdownItem>
<DropdownItem onClick={() => clearForm()}>Clear list</DropdownItem>
<DropdownItem divider />
{watchlists.map((value, index) => (
<DropdownItem value={index} key={value} onClick={() => updateSelected(index)} onMouseEnter={() => setDelWatchlist(true)} onMouseLeave={() => setDelWatchlist(false)}>
<span className="title-watchlists">
{value}
</span>
{delWatchlist && (
<i className="mdi mdi-close-box-outline icon-watchlists" />
)}
</DropdownItem>
))}
</DropdownMenu>
</UncontrolledDropdown>

Use an identifier in delWatchlist.
You could use value, if it is unique. index works, too.
const [delWatchlist, setDelWatchlist] = useState(undefined);
// ...
{watchlists.map((value, index) => (
<DropdownItem
value={index}
key={value}
onClick={() => updateSelected(index)}
onMouseEnter={() => setDelWatchlist(index)}
onMouseLeave={() => setDelWatchlist(current => current === index ? undefined : current)}> // Make sure to only unset itself
<span className="title-watchlists">{value}</span>
{delWatchlist === index && (
<i className="mdi mdi-close-box-outline icon-watchlists" />
)}
</DropdownItem>
))}

Related

How to show/hide buttons onFocus/onBlur below the textarea and allow to click it?

I need to add two buttons below the input field.
One button will allow saving the input in the textarea, and another aborting.
The buttons should be displayed when the input is focused.
Currently, the problem is that when I click any of the buttons, the input gets blurred again and thus they disappear and the onClick event doesn't happen.
I use MUI and Formik.
Can anyone tell me how to fix it?
const [buttonClicked, setButtonClicked] = useState(false);
...
return (
...
<Box sx={inspectionWrapperStyles} mb={'0.25rem'}>
<MultiLineInput
name={fieldName}
noMargin
required={required}
label={label}
onFocus={() => setInputFocused(true)}
onBlur={() => setInputFocused(false)}
ref={inputRef}
/>
{inputFocused && (
<>
<IconButton
altText=""
onClick={() => {
console.log('Saved');
}}
>
<SaveIcon />
</IconButton>
<IconButton
altText=""
onClick={() => {
console.log('Aborted');
}}
>
<XCircleIcon />
</IconButton>
</>
)}
</Box>
...
)
Looks like currently as you click a button the focus of the input is lost, so they disappear. Maybe it's a good idea to check if the button is clicked and only then hide it, like this:
{inputFocused && !buttonClicked (
then in both button's onClick you can add:
onClick={() => {
console.log('Aborted');
setButtonClicked(true);
}}
only thing left is to make sure that we reset it when input is focused again:
onFocus={() => {
setInputFocused(true);
setButtonClicked(false);
}}
const [showButton, setShowButton] = useState(false); // add this
<MultiLineInput
name={fieldName}
noMargin
required={required}
label={label}
onFocus={() =>{
setInputFocused(true)
setShowButton(true) // add this
}}
onBlur={() => setInputFocused(false)}
ref={inputRef}
/>
{inputFocused && showButton && (
<>
<IconButton
altText=""
onClick={() => {
console.log('Saved');
setShowButton(false) // add this if you want to hide buttons
}}
>
<SaveIcon />
</IconButton>
<IconButton
altText=""
onClick={() => {
console.log('Aborted');
setShowButton(false) // add this if you want to hide buttons
}}
>
<XCircleIcon />
</IconButton>
</>
)}

Trying to target one single mapped list item and change its Icon in react

I am trying to change an outlined heart icon to a filled heart icon onClick. I have it working but all the hearts on each card change.
I know I have to try and use the track.id or some sort of id but I just cannot figure out how to do it ?
Any help would be greatly appreciated.
Thank you!
const [clicked, setClicked] = useState(false);
return (
{results.tracks.map(track => (
<IonCard className="IonCard" key={track.id} color=''>
<IonItemGroup translucent>
{clicked?
<IonItem lines="none"
className="card-icons"
key={track.id}
onClick={() =>
setClicked(false)
}
>
<IonIcon
className="card-icons"
icon={heart}
id="disLikeHeart"
slot="start"
value={track.id}
/>
<IonLabel>Discovered Music/>
</IonItem>
:
<IonItem lines="none"
className="card-icons"
key={track.id}
onClick={() =>
setClicked(true)
}
>
<IonIcon
className="card-icons"
icon={heartOutline}
id="likeHeart"
slot="start"
value={track.id}
/>
<IonLabel>Discovered Music</IonLabel>
</IonItem>
}
</>IonItemGroup translucent>
</IonCard>
))}
)
Change your onClick to set clicked to the id
onClick = {()=>setClicked(track.id)}
and then check if the id matches the clicked id
{clicked === track.id ?
<IonItem lines="none"
className="card-icons"
key={track.id}
onClick={() =>
setClicked(false)
}
>

React Native Paper - DataTable get row

How can I get the selected row in React Native Paper DataTables?
My DataTables row mapping:
{sortedItems.slice(from, to).map(item => (
<DataTable.Row key={item.id}>
<DataTable.Cell>{item.numero}</DataTable.Cell>
<DataTable.Cell>{item.data}</DataTable.Cell>
<DataTable.Cell numeric>{item.cliente}</DataTable.Cell>
<DataTable.Cell numeric>
<IconButton
icon="eye"
onPress={() => navigation.navigate('Details', {/* HERE, HOW TO GET THE ELEMENT??? */}}
/>
</DataTable.Cell>
</DataTable.Row>
))}
Just get the item on mapping time:
{sortedItems.slice(from, to).map(item => (
<DataTable.Row key={item.id}>
<DataTable.Cell>{item.numero}</DataTable.Cell>
<DataTable.Cell>{item.data}</DataTable.Cell>
<DataTable.Cell numeric>{item.cliente}</DataTable.Cell>
<DataTable.Cell numeric>
<IconButton
icon="eye"
onPress={() => console.log(item)} /* <--- EASY */
/>
</DataTable.Cell>
</DataTable.Row>
))}

onClick in Map func,only execute for one element

Is there any method for map function to only execute Dropdown menu for one cart.For now if i click on one Menu icon , every dropdown appears for every Card in map.
const [isOpen, setIsOpen] = useState(false);
{albums.map((album, i) => (
<Card width="23rem" height="16rem" bckImg={album.bckImgUrl} key={i}>
<AlbumtTitle color={album.color}>{album.name}</AlbumtTitle>
<LinkButton background={album.color} to={`/albums/${album._id}`}>
See more
</LinkButton>
<KebabMenu onClick={() => setIsOpen(!isOpen)} open={isOpen}>
{isOpen ? (
<Dropdown
ref={ref}
style={{
width: "50px",
height: "50px",
}}
>
<li>
<Link to={`editAlbum/${album._id}`}>Edit</Link>
</li>
<hr />
<li>Delete</li>
</Dropdown>
) : (
<Dots />
)}
</KebabMenu>
</Card>
))}
Your isOpen state can be an object that tracks the open state per item in the album:
const [isOpen, setIsOpen] = useState({});
{albums.map((album, i) => (
<Card width="23rem" height="16rem" bckImg={album.bckImgUrl} key={i}>
<AlbumtTitle color={album.color}>{album.name}</AlbumtTitle>
<LinkButton background={album.color} to={`/albums/${album._id}`}>
See more
</LinkButton>
<KebabMenu
onClick={() =>
setIsOpen({ ...isOpen, [album._id]: !isOpen[album._id] })
}
open={!!isOpen[album._id]}
>
{isOpen[album._id] ? (
<Dropdown
ref={ref}
style={{
width: "50px",
height: "50px",
}}
>
<li>
<Link to={`editAlbum/${album._id}`}>Edit</Link>
</li>
<hr />
<li>Delete</li>
</Dropdown>
) : (
<Dots />
)}
</KebabMenu>
</Card>
))}
Instead of
{albums.map((album, i) => (...your code...))}
you need to check whether you have at least one item in albums, and if yes, process it:
{if (albums.length > 0) {
return albums.slice(0,1).map((album, i) => (...your code...))
} else {
return null // or any other actions you want to take in case there are no albums
}
}
To clarify, we check the length of the albums, if it is not empty. If it is, we take only the first element and process it.

React trigger only one element in array

I am in the process of making a comment system like the one on youtube. In my implementation, when I click on modify, all comments are now inputs but only the value of the selected input will be modified. how to trigger only the element i clicked.
as you can see it triggers all the array elements
function App() {
const [open, setOpen] = useState(false);
return (
<div className="container mt-5">
<MDBRow>
{data &&
data.map((item) => (
<MDBCol md="7" lg="7" key={item.id} className="mb-4">
{!open && (
<>
<div className="font-weight-bolder float-left pr-2">
{item.name}
</div>
<div className="float-right pr-2">
<button
onClick={() => {
setOpen(true);
}}
>
Modifier
</button>
</div>
</>
)}
{open && (
<UpdateData
id={item.id}
name={item.name}
onAbort={() => setOpen(false)}
submit={() => setOpen(false)}
/>
)}
</MDBCol>
))}
</MDBRow>
</div>
);
}
export const UpdateData = ({ name, id, onAbort, submit }) => {
const formik = useFormik({
initialValues: {
id: id,
name: name,
},
onSubmit: async (values) => {
console.log(values);
submit();
},
});
return (
<form onSubmit={formik.handleSubmit}>
<MDBInput
value={formik.values.name}
name="name"
onChange={formik.handleChange}
/>
<div className="float-right">
<span onClick={onAbort} className="text-capitalize grey-text">
Cancel
</span>
<button type="submit">confirm</button>
</div>
</form>
);
};
And this is the sandbox
that i have created
To trigger only one element to be clicked you have to pass the index
function App() {
const [open, setOpen] = useState(false);
const [selectedRow, setSelectedRow] = useState(undefined);
const onSelectedRow = (index) => {
setSelectedRow(index);
setOpen(true);
}
return (
<div className="container mt-5">
<MDBRow>
{data &&
// here you will get the index
data.map((item,index) => (
<MDBCol md="7" lg="7" key={item.id} className="mb-4">
{!open && (
<>
<div className="font-weight-bolder float-left pr-2">
{item.name}
</div>
<div className="float-right pr-2">
// Now onClick pass the index of selected row to onSelectedRow
<button
onClick={() =>onSelectedRow(index)}
>
Modifier
</button>
</div>
</>
)}
// here add condition to open selected row
{ (open === true && selectedRow === index) ? (
<UpdateData
id={item.id}
name={item.name}
onAbort={() => setOpen(false)}
submit={() => setOpen(false)}
/>
) : null
}
</MDBCol>
))}
</MDBRow>
</div>
);
}
Sandbox code https://codesandbox.io/s/youthful-wave-k4eih?file=/src/App.js
If you have any queries comment below!
instead of having a false default value in your hook you should have a unique key for each element. By default, it applies to all elements.

Categories

Resources