Code:-
const myRef = React.createRef([]);
const handleKeyDown = (event, ID) => {
//up and Down key
const active = document.activeElement;
active.addEventListener('keydown', function (event) {
switch (event.key) {
case "ArrowUp":
active?.previousElementSibling?.focus();
event.preventDefault();
break;
case "ArrowDown":
active?.nextElementSibling?.focus();
event.preventDefault();
break;
default: break;
}
});
}
const active = () => {
myRef.current.focus()
}
return (
<div className="mainContent">
<div className="tableHeaderBody">
<div className="TableText">PlayList</div> <div className="ClossIcon"><FaCircle style={{ color: "#FC0000", width: "10px", height: "10px", alignItems: "right" }} /></div>
</div>
<div className="tableBody" >
<table className="table">
<Header
headers={headers}
/>
<tbody>
{comments.map((comment) => {
//Display Hex to base64 image format
const base64 = Buffer.from(comment.Thumbnail, 'hex').toString('base64');
//console.log(base64);
const statusContent = () => {
if (comment.Status === 0) {
return <div><BsFillCircleFill style={{ color: "#FF0000", width: "20px" }} /> Not Ready</div>;
} else if (comment.Status === 1) {
return <div><BsFillCircleFill style={{ color: "#41fc00", width: "20px" }} /> Ready</div>;
} else if (comment.Status === 2) {
return <button type="Submit" style={{ backgroundColor: "blue" }}>Cueing</button>;
} else if (comment.Status === 3) {
return <button type="Submit" style={{ backgroundColor: "yellow", color: "Black" }}>Cued</button>;;
} else {
return <button type="Submit">Playing</button>;
}
};
return (
<tr key={comment.idx} tabIndex={comment.idx} className="border_bottom" onKeyDown={(e) => handleKeyDown(e, comment.idx)} onLoad={() => active()} ref={myRef}>
<td style={{ color: "white", width: "200px" }}>
<img src={`data:image/jpeg;base64,${base64}`} alt="Clip Thumbnail" width="100%" />
</td>
<td style={{ color: "white", width: "440px" }}>{comment.ClipName}</td>
i using myRef.current.focus() in active = () but it's show me focus in last row when i load the page
i want that when page load focus show in first row and user use up and down key in table row without clicking the table row
enter image description here
As i load the page focus automatically placed in last row show in image how to fix that? please help
What I think is happening, is that onLoad triggers for every rendered row. So when the last row is rendered it is the last time onLoad triggers and focuses on this row. To overcome this issue:
const active = (rowNumber) => {
if (rowNumber === 0) {
myRef.current.focus()
}
}
And in the tag in the onLoad pass it as:
<tr key={comment.idx} tabIndex={comment.idx} className="border_bottom" onKeyDown={(e) => handleKeyDown(e, comment.idx)} onLoad={() => active(comment.idx)} ref={comment.idx === 0 && myRef}>
You are giving all rendered row the same ref, that might cause an issue too so I conditioned it to give the ref only to the first row.
Related
I'm writing a code where I'm using react-range to create a range bar. along with it, I've got 2 textboxes that have the min and max values of the range. Currently, I'm able to update the range values by dragging and the text boxes get updated automatically. And I also want to update the price range using the textboxes mentioned, currently, the min box value works fine, but, when I try to update the max value, the value gets appended instead of updating. Unable to know where I'm going wrong.
Here is the code of the same.
import { useState } from "react";
import { Range, getTrackBackground } from "react-range";
export const PriceRange = () => {
const [priceValues, setPriceValues] = useState([1, 100]);
let step = 1;
const handleChange = (values: number[]) => {
if (values[0] > values[1]) {
values[0] = values[1];
}
if (values[1] < values[0]) {
values[1] = values[0];
}
setPriceValues(values);
};
return (
<>
{
<div
style={{
width: "50%",
maxWidth: "50%",
marginLeft: "auto",
marginRight: "auto"
}}
>
<div className="mb-8 text-gray-900 text-sm font-medium text-left">
Price
</div>
<div
style={{ padding: "1rem", marginTop: "1rem", marginBottom: "1rem" }}
>
<Range
step={step}
min={priceValues[0]}
max={priceValues[1]}
values={priceValues}
onChange={(values) => handleChange(values)}
renderTrack={({ props, children }) => (
<div
{...props}
style={{
...props.style,
background: getTrackBackground({
values: priceValues,
colors: ["#c4c4c442", "black", "#c4c4c442"],
min: priceValues[0],
max: priceValues[1]
}),
height: "0.5rem",
width: "100%"
}}
>
{children}
</div>
)}
renderThumb={({ index, props }) => (
<div
{...props}
style={{
...props.style
}}
className="thumbs"
>
<div className="priceValues">{`$${
priceValues[index] === priceValues.length - 1
? priceValues[index] + "+"
: priceValues[index]
}`}</div>
</div>
)}
/>
</div>
<div className="rangeBoxesContainer">
<div className="rangeBox">
<div style={{ display: "flex" }}>Min $</div>
<input
className="rangeInputbox"
type="number"
value={priceValues[0]}
onChange={(e) => {
if (Number(e.target.value) < Number(priceValues[1])) {
let newValue = [...priceValues];
newValue[0] = Number(e.target.value);
setPriceValues(newValue);
}
}}
/>
</div>
<div className="rangeBox">
<div style={{ display: "flex" }}>Max $</div>
<input
className="rangeInputbox"
type="number"
value={priceValues[1]}
onChange={(e) => {
if (Number(e.target.value) > Number(priceValues[1])) {
let newValue = [...priceValues];
newValue[1] = Number(e.target.value);
setPriceValues(newValue);
}
}}
/>
</div>
</div>
</div>
}
</>
);
};
And here is a working code sandbox link. Can someone let me know where I'm going wrong?
Thanks
how can I add the All checkboxes that will select all the other checkboxes for each Type of plant and adding a checkbox in front of each Type of plant section. So when I select one option Plant 1.1 then my checkbox for Type of plant #1 is filled, and if option is filled then the checkbox for Type of plant is not filled.
export default function Category({
_id_type,
name_type,
plants,
changeSelection
}) {
const [toggleState, setToggleState] = 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>
);
}
Here a picture (what I have/ what I want) :
Here is my code
add new toogle inside category.jsx
{toggleState && plants.length > 1 ? (
<div>
<input
type="checkbox"
value={"all"}
checked={allSelected}
onChange={(e) => {
setAllSelected((v) => {
changeSelection(_id_type, "all", e.target.value, !v);
return !v;
});
}}
/>
All
</div>
) : (
""
)}
edit change selection function:
const changeSelection = (catId, itemId, value, allSelected) => {
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 };
} else if (itemId === "all") {
return { ...plant, selected: allSelected };
}
return plant;
})
};
}
return item;
})
);
};
here the forked code:
https://codesandbox.io/embed/plants-forked-qdmz2h?fontsize=14&hidenavigation=1&theme=dark
I want to synchronize a divs scroll with a body scroll.
I tried some examples with two divs but I couldn't manage fix it with the body scroll.
Sample code with two divs: https://codesandbox.io/s/react-custom-scroll-sync-of-2-divs-10xpi
My Code
https://codesandbox.io/s/funny-rain-ditbv
import "./styles.css";
import { useRef } from "react";
export default function App() {
const firstDivRef = useRef();
const secondDivRef = useRef();
const handleScrollFirst = (scroll) => {
secondDivRef.current.scrollTop = scroll.target.scrollTop;
};
const handleScrollSecond = (scroll) => {
firstDivRef.current.scrollTop = scroll.target.scrollTop;
};
return (
<div
className="App"
style={{
display: "flex",
}}
>
<div
onScroll={handleScrollFirst}
ref={firstDivRef}
style={{
height: "500px",
overflow: "scroll",
backgroundColor: "#FFDAB9",
position: "sticky",
top: "0px"
}}
>
<div style={{ height: 5000, width: 300 }}>
The first div (or it can be tbody of a table and etc.)
{[...new Array(1000)].map((_, index) => {
const isEven = index % 2 === 0;
return (
<div style={{ backgroundColor: isEven ? "#FFFFE0 " : "#FFDAB9" }}>
{index}
</div>
);
})}
</div>
</div>
<div
onScroll={handleScrollSecond}
ref={secondDivRef}
style={{
height: "100%",
backgroundColor: "#EEE8AA"
}}
>
<div style={{ height: 5000, width: 200 }}>
The second div
{[...new Array(1000)].map((_, index) => {
const isEven = index % 2 === 0;
return (
<div style={{ backgroundColor: isEven ? "#FFFFE0 " : "#FFDAB9" }}>
{index}
</div>
);
})}
</div>
</div>
</div>
);
}
It was easy to use different divs rather than using a div and window.
But finally managed to run it with a div and the body.
The trick is they block each other since they listen each others values.
import "./styles.css";
import { useEffect, useRef, useState } from "react";
export default function App() {
const firstDivRef = useRef();
const [scrollTop, setScrollTop] = useState(0);
const [disableBodyScroll, setDisableBodyScroll] = useState(false);
const handleScrollFirst = (scroll) => {
setScrollTop(scroll.target.scrollTop);
};
useEffect(() => {
if (firstDivRef.current && !disableBodyScroll) {
firstDivRef.current.scrollTop = scrollTop;
}
if (disableBodyScroll) {
window.scrollTo(0, scrollTop);
}
}, [firstDivRef, scrollTop, disableBodyScroll]);
useEffect(() => {
const onScroll = () => {
console.log(disableBodyScroll, window.scrollY);
if (!disableBodyScroll) {
setScrollTop(window.scrollY);
}
};
// clean up code
window.removeEventListener("scroll", onScroll);
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, [disableBodyScroll]);
return (
<div
className="App"
style={{
display: "flex"
}}
>
<div
onMouseEnter={() => setDisableBodyScroll(true)}
onMouseLeave={() => setDisableBodyScroll(false)}
onScroll={handleScrollFirst}
ref={firstDivRef}
style={{
height: "500px",
overflow: "scroll",
backgroundColor: "#FFDAB9",
position: "sticky",
top: "0px"
}}
>
<div style={{ height: 5000, width: 300 }}>
The first div (or it can be tbody of a table and etc.)
{[...new Array(1000)].map((_, index) => {
const isEven = index % 2 === 0;
return (
<div style={{ backgroundColor: isEven ? "#FFFFE0 " : "#FFDAB9" }}>
{index}
</div>
);
})}
</div>
</div>
<div
style={{
height: "100%",
backgroundColor: "#EEE8AA"
}}
>
<div style={{ height: 5000, width: 200 }}>
The second div
{[...new Array(1000)].map((_, index) => {
const isEven = index % 2 === 0;
return (
<div style={{ backgroundColor: isEven ? "#FFFFE0 " : "#FFDAB9" }}>
{index}
</div>
);
})}
</div>
</div>
</div>
);
}
https://codesandbox.io/s/ancient-dream-tzuel?file=/src/App.js
Try the next example. This is a quick sketch but maybe it will help you.
https://codesandbox.io/s/gallant-goldwasser-19g4d?file=/src/App.js
Objective is to have an array with captured pokemons if user clicks on the input and an array of not-captured pokemons if user un-clicks the input. I've managed to filter out the pokemon when it's no longer captured and have it in the not-captured array but I can't seem to delete that pokemon from the old captured array.
Eg. If I click on "bulbasaur", "charmender", "squirtle", I get them all in the captured array. If I then remove one of them, I correctly get the removed one in the not-captured array but I can't seem to delete it from the previous captured array.
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import PokemonIcon from "./PokemonIcon";
const PokemonCard = ({ pokemon, capturedPkm, setCapturedPkm, notCapturedPkm, setNotCapturedPkm }) => {
const [label, setLabel] = useState('Not captured')
const toggleCaptured = (checked, id) => {
const pokemonName = { id: pokemon.id, name: pokemon.name }
if (checked && id === pokemon.id) {
setCapturedPkm([...capturedPkm, pokemonName])
setLabel('Captured!')
} else {
setLabel('Not captured!')
setNotCapturedPkm([...notCapturedPkm, pokemonName])
if (checked === false) {
let newArr = [...capturedPkm]
let pkmRemoved = newArr.filter((el, i) => el.id === id)
let newArrPkm = newArr.splice(pkmRemoved, 1)
console.log('newArr',newArrPkm, 'pkmRemoved', pkmRemoved)
setCapturedPkm(newArrPkm)
}
}
}
useEffect(() => {
console.log('captured', capturedPkm, 'not captured', notCapturedPkm)
}, [capturedPkm, notCapturedPkm])
return (
<>
<div
className="pokemon-card"
style={{
height: "250px",
maxWidth: "250px",
margin: "1rem",
boxShadow: "5px 5px 5px 4px rgba(0, 0, 0, 0.3)",
cursor: "pointer",
}}
>
<Link
to={{ pathname: `/pokemon/${pokemon.id}` }}
style={{ textDecoration: "none", color: "#000000" }}
state={{ pokemon: pokemon, capturedPkm }}
>
<div
style={{
padding: "20px",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<PokemonIcon img={pokemon.sprites?.['front_default']} />
</div>
</Link>
<div style={{ textAlign: "center" }}>
<h1>{pokemon.name}</h1>
<label>
<input type="checkbox"
defaultChecked={false}
value={pokemon.name}
onChange={(e) => toggleCaptured(e.target.checked, pokemon.id)} />
<span style={{ marginLeft: 8, cursor: 'pointer' }}>
{label}
</span>
</label>
</div>
</div>
<div></div>
</>
);
};
export default PokemonCard;
I guess you forgot to update the notCapturedPkm array. You could try something like this :
if (checked && id === pokemon.id) {
setCapturedPkm([...capturedPkm, pokemonName])
// Update this array, by removing the selected pokemon
setNotCapturedPkm([...notCapturedPkm.filter(pkm => pkm.id !== pokemon.id)])
setLabel('Captured!')
}
I have created a MERN application in which on dashboard when a button is clicked a modal box opens which contains some inputs and some options to be selected which are handled using react state hooks. I want when I close modal box the value in it should be reset to default one and when i reopen it all the options should reset to default value
Here is my modal box code
import React, { useState, useContext, useEffect } from "react";
import { UserContext } from "./UserContext";
function SplitModal({
setsplitmodal,
cost,
list,
listobj,
setlistobj,
equal,
setEqual,
payer,
setPayer,
part,
setPart,
setM,
}) {
const [method, setMethod] = useState(true);
const [split, setsplit] = useState(true);
const [owe, setowe] = useState(true);
const [owes, setowes] = useState(true);
const [click, setClick] = useState(false);
const [amount, setAmount] = useState();
const [total, setTotal] = useState(0);
const { user, userfriend } = useContext(UserContext);
console.log(user, "user hu darta koni", user.name);
console.log(listobj);
useEffect(() => {
if (equal === "unequally") {
const _listobj = { ...listobj };
Object.keys(listobj).map((f) => {
_listobj[f] = 0;
});
setlistobj(_listobj);
document.getElementById("InputId").value = "";
console.log(_listobj, "listobjsehu");
}
}, [list, cost]);
const func1 = () => {
setM(false);
setEqual("unequally");
setMethod(false);
const _list = { ...listobj };
_list[list[0]] = -cost;
_list[list[1]] = cost;
setlistobj(_list);
setowe(false);
setowes(true);
setPayer(list[1]);
setPart(`(You owe ${list[1]} ₹${cost})`);
};
const func2 = () => {
setM(false);
setEqual("unequally");
setMethod(false);
const _list = { ...listobj };
const b = _list[list[0]];
_list[list[0]] = +cost;
_list[list[1]] = -cost;
setlistobj(_list);
setPayer(list[0]);
setowe(true);
setowes(false);
setPart(`(${list[1]} owes you ₹${cost})`);
// console.log(owe, owes, click);
};
const distriequal = () => {
setM(true);
// setowe(true);
// setowes(true);
setPart(`(₹${(cost / list.length).toFixed(2)}/person)`);
setMethod(true);
setEqual("equally");
setTotal(0);
const _list = { ...listobj };
list.map((f) => {
if (f === payer) {
_list[f] = (cost - cost / list.length).toFixed(2);
} else {
_list[f] = -(cost / list.length).toFixed(2);
}
setlistobj(_list);
});
};
// console.log(listobj.exp[list[1]], listobj);
const distriamount = (e, i) => {
if (e.key === "Backspace") setM(true);
if (parseInt(e.target.value) > cost) setAmount("err");
else setAmount("");
// console.log( a.replace(a,e.targetvalue));
const _list = { ...listobj };
if (list[i] === payer) {
// _list[list[i]] = e.target.value;
// setOwner(e.target.value);
_list[payer] = parseInt(cost - e.target.value);
} else {
_list[list[i]] = -e.target.value;
}
setlistobj(_list);
if (listobj[user.name] > 0)
setPart(`You get back ₹${Math.abs(_list[user.name])}`);
else if (listobj[user.name] < 0)
setPart(`You owe ₹${Math.abs(_list[user.name])}`);
else setPart(`You owe nothing`);
};
// useEffect(() => {
// Object.keys(listobj).map((f) => {
// if (f === user.name) {
// console.log("nmnm");
// setTotal(total + owner);
// } else setTotal(total + Math.abs(listobj[f]));
// });
// }, [listobj]);
console.log(listobj, list);
return (
<div>
<div className="splitmodal">
<div
style={{
backgroundColor: "#1cc29f",
border: "1px solid #eeeeee",
padding: "5px",
display: "flex",
borderRadius: "10px 10px 0px 0px",
color: "white",
}}
>
<h5 style={{ marginLeft: "100px" }}>Choose Payer</h5>
<button
style={{ position: "absolute", right: "10px" }}
onClick={() => {
setsplitmodal(false);
}}
>
<i class="fas fa-times" />
</button>
</div>
{list.length === 2 ? (
<div className="bg-white splitmodal-main1">
<button
onClick={() => {
setMethod(true);
setM(true);
setClick();
setowe(true);
setowes(true);
}}
>
Split the expense
</button>
<button
onClick={() => {
{
setClick("owe");
return owe ? func1() : null;
}
}}
className={click === "owe" ? "click" : null}
>
You owe {list[1]} ₹{cost}
</button>
<button
className="mb-2"
onClick={() => {
{
setClick("owes");
return owes ? func2() : null;
}
}}
className={click === "owes" ? "click" : null}
>
{list[1]} owes you ₹{cost}
</button>
</div>
) : null}
{method ? (
<div className="splitmodal-main2">
<hr style={{ margin: "10px" }} />
<div className="flex justify-content-center">
<button
style={{
border: "1px solid #ccc",
borderRadius: "5px 0px 0px 5px",
}}
className={equal === "equally" ? "select" : "deselect"}
onClick={() => {
distriequal();
}}
>
Split equally
</button>
<button
style={{
border: "1px solid #ccc",
borderRadius: "0px 5px 5px 0px",
}}
className={equal === "unequally" ? "select" : "deselect"}
onClick={() => {
setEqual("unequally");
}}
>
Split by amounts
</button>
</div>
{equal === "equally" ? (
<div>
<div className="splitmodal-main3">
<h5 className="mt-2 ml-3">Split equally</h5>
<ul
style={{
display: "flex",
flexDirection: "column",
marginLeft: "10px",
}}
>
{list.map((f) => {
return (
<li className="flex align-items-center m-2">
<img
src="https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-grey47-50px.png"
alt=""
/>
<span className="ml-2 font-bold">{f}</span>
<span className="absolute right-10 ">
₹{cost ? (cost / list.length).toFixed(2) : 0.0}
</span>
</li>
);
})}
</ul>
</div>
</div>
) : (
<div>
<div className="splitmodal-main3">
<h5 className="mt-2 ml-3">Split by amounts</h5>
<ul
style={{
display: "flex",
flexDirection: "column",
marginLeft: "10px",
}}
>
{list.map((f, i) => {
return (
<li key={i} className="flex align-items-center m-2">
<img
src="https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-grey47-50px.png"
alt=""
/>
<span className="ml-2 font-bold">{f}</span>
<span className="absolute right-5 ">
<span
style={{
backgroundColor: "#EEEEEE",
paddingLeft: "14px",
paddingRight: "14px",
border: "1px solid #ccc",
borderRadius: "4px 0px 0px 4px",
}}
>
₹
</span>
<input
type="number"
// value={Math.abs(listobj[f])}
id="InputId"
style={{
width: "60px",
border: "1px solid #ccc",
borderRadius: "0px 4px 4px 0px",
height: "23.33px",
}}
className={
amount === "err" ? "text-red-500" : null
}
onChange={(e) => {
distriamount(e, i);
}}
/>
</span>
</li>
);
})}
</ul>
</div>
{/* <div className="mt-2 ml-3">
<h5>Total:</h5>
<span className="absolute right-10 bottom-0 ">₹{total}</span>
</div> */}
</div>
)}
</div>
) : null}
</div>
</div>
);
}
export default SplitModal;
Please help me solving this
As a workaround you can write a new useEffect() that reset all the value at the loading of your component, something like :
useEffect(() => {
setMethod(true);
setsplit(true);
setowe(true);
setowes(true);
setClick(false);
setAmount();
setTotal(0);
}, []);
We don't actually need a separate effect to perform the cleanup. useEffect is designed to keep it together.
Learn more on: https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup
useEffect(() => {
// your other codes
return function reset() {
setMethod(true);
setsplit(true);
setowe(true);
setowes(true);
setClick(false);
setAmount(0);
setTotal(0);
}
}, []);