For some reason, this code works:
const Task = ({task, onDelete, onToggle}) => {
return (
<div className="task"
onClick={() => onToggle(task.id)}>
</div>
But this one doesn't:
const Task = ({task, onDelete, onToggle}) => {
return (
<div className="task"
onDoubleClick={() => onToggle(task.id)}>
</div>
The rest of the code is this, if it helps:
App.js
const toggleReminder = (id) => {
console.log("double click!", id);
}
return (
<div className="container">
<Header title="Task Tracker"/>
{tasks.length > 0 ? (
<Tasks tasks={tasks} onDelete={deleteTask} onToggle={toggleReminder}/>
) : ("No Tasks to show")
}
Tasks.js
const Tasks = ({ tasks, onDelete, onToggle }) => {
return (
<>
{tasks.map((task, index) => (
<Task key={index} task={task} onDelete={onDelete} onToggle={onToggle} />
))}
</>
)
}
And Task.js
const Task = ({task, onDelete, onToggle}) => {
return (
<div className="task"
onDoubleClick={() => onToggle(task.id)}>
<h3>{task.text}
<FaTimes
style={{color:"red", cursor: 'pointer'}}
onClick={()=> onDelete(task.id)}/>
</h3>
<p>{task.day}</p>
</div>
)
}
I've been copying everything from a tutorial, and I really don't understand the problem. With onClick it works just fine. Do they work differently?
I saw a similar question but did not understand the answer
Thank you!
Related
I am trying to make history by pushing on button click
onclick function of the li is not working
as u can see in the code <SuggestionsList/> is in the last return statement its funtions are rendered in const SuggestionsList = (props) => { . The onclick funtion is comimg inside the const SuggestionsList funtion, this is making the onclick funtion not working
i created the exact working in codesand and its working there without any problem i dont get why its not working in my local
enter link description here
function finddoctor(e) {
console.log(e);
history.push(`/detiled/${e} `);
}
const onChange = (event) => {
const value = event.target.value;
setInputValue(value);
setShowResults(false);
const filteredSuggestions = suggestions.filter(
(suggestion) =>
suggestion.firstname
.toString()
.toLowerCase()
.includes(value.toLowerCase()) ||
suggestion.id.toString().toLowerCase().includes(value.toLowerCase())
);
setFilteredSuggestions(filteredSuggestions);
setDisplaySuggestions(true);
};
const onSelectSuggestion = (index) => {
setSelectedSuggestion(index);
setInputValue(filteredSuggestions[index]);
setFilteredSuggestions([]);
setDisplaySuggestions(false);
};
const SuggestionsList = (props) => {
const {
suggestions,
inputValue,
onSelectSuggestion,
displaySuggestions,
selectedSuggestion,
} = props;
if (inputValue && displaySuggestions) {
if (suggestions.length > 0) {
return (
<ul className="suggestions-list" style={styles.ulstyle}>
{suggestions.map((suggestion, index) => {
const isSelected = selectedSuggestion === index;
const classname = `suggestion ${isSelected ? "selected" : ""}`;
return (
<>
<li
style={styles.listyle}
onClick={finddoctor(suggestion.id)}
key={index}
className={classname}
>
{suggestion.firstname}
</li>
</>
);
})}
</ul>
);
} else {
return <div>No suggestions available...</div>;
}
}
return <></>;
};
useEffect(() => {
axios
.get("admin-panel/all-doctors-list/")
.then((res) => {
const data = res.data;
setShowSerch(data);
});
}, []);
return (
<>
<div className="note-container" style={styles.card}>
<div style={styles.inner}>
<p style={{ textAlign: "left" }}>Search Doctors</p>
<form className="search-form" style={{}}>
{showResults ? (
<FontAwesomeIcon
style={{ marginRight: "-23px" }}
icon={faSearch}
/>
) : null}
<input
onChange={onChange}
value={inputValue}
style={styles.input}
type="Search"
/>
<SuggestionsList
inputValue={inputValue}
selectedSuggestion={selectedSuggestion}
onSelectSuggestion={onSelectSuggestion}
displaySuggestions={displaySuggestions}
suggestions={filteredSuggestions}
/>
</form>
</div>
</div>
</>
);
};
Instead of onClick={finddoctor(suggestion.id)} (Here just function invocation is happening and expected to have the callback method)
should be
onClick={() => finddoctor(suggestion.id)}
I have implemented a simple drag and drop code here below using react-beautiful-dnd. The frontend alone works perfectly fine, however, when I tried to connect this with the backend the items in the droppable context are unable to be dragged. That is, I am unable to drag the items within the column and also between columns. Further, I am unable to figure out how to pass the index of the elements in the mongoDb database.
The code I used is here below
projectsDashboard.js
function ProjectsDashboard() {
const handleDragEnd = ({destination, source}) => {
if (!destination) {
return
}
if (destination.index === source.index && destination.droppableId === source.droppableId) {
return
}
// Creating a copy of item before removing it from state
const itemCopy = {...state[source.droppableId].items[source.index]}
setState(prev => {
prev = {...prev}
// Remove from previous items array
prev[source.droppableId].items.splice(source.index, 1)
// Adding to new items array location
prev[destination.droppableId].items.splice(destination.index, 0, itemCopy)
return prev
})
}
const dispatch = useDispatch();
useEffect(() => {
dispatch(getStages());
},[dispatch]);
const { stage } = useSelector(state => state.stage);
var formattedArray = stage.map(item => Object.keys(item).map(i => item[i]));
console.log(formattedArray)
return (
<DragDropContext onDragEnd={handleDragEnd}>
{_.map(state, (data, key) => {
return(
<div key={key} className={"column"}>
{console.log(key , "KEY")}
<ProjectWrapper className="border">
<h3 className="title">{data.title}</h3>
</ProjectWrapper>
<Droppable droppableId={key}>
{(provided, snapshot) => {
return(
<div>
<div
ref={provided.innerRef}
{...provided.droppableProps}
className={"droppable-col"}
>
<hr className="line" style={{opacity: 10 }}></hr>
{stage.map(stages=>{
if(stages.status == key)
return(
<Draggable key={stages._id}
//index={index}
draggableId={stages._id} className="drag">
{(provided, snapshot) => {
console.log(snapshot)
return(
<div
className={`item ${snapshot.isDragging && "dragging"}`}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
{/* card name */}
<button className="stageDetails" style={{padding: "0",border: "none", background: "none"}}>
{stages.stageName}
</button>
<DeleteOutlinedIcon className="delete" />
</div>
)
}}
</Draggable>
)
})}
{provided.placeholder}
</div>
</div>
)
}}
</Droppable>
</div>
)
})}
</DragDropContext>
</div>
);
};
export default ProjectsDashboard;
I have list of products. I want to display only products that have a description or name containing typed word by clicking enter on search input.
So I tried this in my Search component
const Search = (props) => {
return (
<InputGroup className="container custom-input-group">
<FontAwesomeIcon icon={faSearch} className="icon" />
<FormControl
placeholder="Search"
type="text"
className="mr-sm-2"
onChange={(e) => props.onSearch(e.target.value)}
value={props.value}
/>
</InputGroup>
);
};
And this in my Appcomponent
const App = (props) => {
const [cartProducts, setCartProducts] = useState([]);
const [products, setProducts] = useState(getProducts());
const [searchValue, setSearchValue] = useState();
const handleAddProductToCart = (productID) => {
console.log(productID);
setCartProducts([...cartProducts, productID]);
};
const handleRemoveFromCart = (productID) => {
const newCartProducts = cartProducts.filter((id) => id !== productID);
setCartProducts(newCartProducts);
};
const filterItems = ({ description, title }) => {
return title.toLocaleLowerCase().indexOf(searchValue.toLocaleLowerCase())
|| description.toLocaleLowerCase().indexOf(searchValue.toLocaleLowerCase())
}
return (
<>
<Header />
<Search onSearch={setSearchValue} value={searchValue} />
{products.filter(filterItems).map((product, id) => (
<Product key={product.id} {...product}/>
))}
<Sidebar />
{products.map((product) => {
const { id } = product;
let haveInCart = false;
cartProducts.forEach((productID) => {
if (productID === id) {
haveInCart = true;
}
});
return (
<Product
key={product.id}
product={product}
handleAddProductToCart={handleAddProductToCart}
/>
);
})}
<h2>Your Cart</h2>
{cartProducts.length > 0
? cartProducts.map((productID) => {
const productIndex = products.findIndex((product) => {
return product.id === productID;
});
let product = products[productIndex];
return (
<CartProduct
key={product.id}
product={product}
handleRemoveFromCart={handleRemoveFromCart}
haveInCart={true}
/>
);
})
: "Yor Cart is Empty :("}
</>
);
};
It's giving me SyntaxError. What am I doing wrong?
Code sandbox
https://codesandbox.io/s/cat-toys-n23m6?file=/src/App.jsx:275-2222
EDIT I found I was missing ))} but it's still not working
Add an empty tag in your map function
{
products.filter(filterItems).map((product, id) => (
<> {/* here */}
<Product key={product.id} {...product}/>
<Sidebar />
{
products.map((product) => {
const { id } = product;
let haveInCart = false;
cartProducts.forEach((productID) => {
if (productID === id) {
haveInCart = true;
}
});
return (
<Product
key={product.id}
product={product}
handleAddProductToCart={handleAddProductToCart}
/>
);
})
}
</> {/* here */}
))}
EDIT
I have made changes to your code. Now it's your turn ;)
Demo: stackblitz
I forked your sandbox. Here's the code
return (
<>
<Header />
<Search onSearch={setSearchValue} value={searchValue} />
{products.filter(filterItems).map((product, id) => (
<div>
<Product key={product.id} {...product} />
<Sidebar />
{products.map((product) => {
const { id } = product;
let haveInCart = false;
cartProducts.forEach((productID) => {
if (productID === id) {
haveInCart = true;
}
});
return (
<Product
key={product.id}
product={product}
handleAddProductToCart={handleAddProductToCart}
/>
);
})}
<h2>Your Cart</h2>
{cartProducts.length > 0
? cartProducts.map((productID) => {
const productIndex = products.findIndex((product) => {
return product.id === productID;
});
let product = products[productIndex];
return (
<CartProduct
key={product.id}
product={product}
handleRemoveFromCart={handleRemoveFromCart}
haveInCart={true}
/>
);
})
: "Yor Cart is Empty :("}
</div>
))}
</>
);
I have a list of Child objects mapped from my Parent component in my React App.
When a Child item is clicked, I need the props.name of that item to be pushed to the selectedItems array in the Parent component via the handleClick function.
How can I achieve this?
function Parent() {
let selectedItems = [];
const result = Data.filter((e) => selectedItems.includes(e.id));
return (
<div className="App">
<main className="products-grid flex flex-wrap">
{Data.map((item, i) => {
return <Child
key={item.id}
name={item.name} />
})}
</main>
</div>
);
}
export default App
const Child = (props) => {
const [clickCount, setClickCount] = useState(0);
function handleClick() {
setClickCount(prevClickCount => prevClickCount + 1);
}
return (
<div
className="product"
onClick={() => handleClick()}
>
<p>{props.name}</p>
<p>{clickCount > 0 ? <p>Selected: {clickCount}</p> : <p>Not Selected</p>}</p>
<img src={props.img} alt="" />
</div>
);
}
I would recommend using hooks for the 'selectedItems' in the parent component, as to trigger a re-render when the name changes.
You can pass functions from the parent to the child component using props.
Below I've passed the 'addToSelectedItems' function down to the child and triggered it in the handleClick method.
const Parent = () => {
const [selectedItems, setSelectedItems] = useState([]);
function addToSelectedItems(name){
setSelectedItems([...selectedItems, name]);
}
return (
<div className="App">
<main className="products-grid flex flex-wrap">
{Data.map((item, i) => {
return <Child
key={item.id}
name={item.name}
addToSelectedItems={addToSelectedItems}
/>
})}
</main>
</div>
);
}
export default App
const Child = (props) => {
const [clickCount, setClickCount] = useState(0);
function handleClick(name) {
setClickCount(prevClickCount => prevClickCount + 1);
props.addToSelectedItems(name);
}
return (
<div
className="product"
onClick={(props.name) => handleClick(props.name)}
>
<p>{props.name}</p>
<p>{clickCount > 0 ? <p>Selected: {clickCount}</p> : <p>Not Selected</p>}</p>
<img src={props.img} alt="" />
</div>
);
}
I'd do something like this, but I have not tested it, it might need some fine tuning
function Parent() {
let selectedItems = [];
const result = Data.filter((e) => selectedItems.includes(e.id));
const [clickCount, setClickCount] = useState(0);
function handleClick(name) {
setClickCount(prevClickCount => prevClickCount + 1);
selectedItem.push(name)
}
return (
<div className="App">
<main className="products-grid flex flex-wrap">
{Data.map((item, i) => {
return <Child
key={item.id}
name={item.name}
clickCount={clickCount}
handleClick={handleClick} />
})}
</main>
</div>
);
}
export default App;
const Child = (props) => {
let { handleClick, name, clickCount, img } = props
return (
<div
className="product"
onClick={() => handleClick(name)}
>
<p>{name}</p>
<p>{clickCount > 0 ? <p>Selected: {clickCount}</p> : <p>Not Selected</p>}</p>
<img src={img} alt="" />
</div>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
See that loop loading two components. I would like to display only <Image /> by default, but when I click this element, I want it to turn into <YouTube /> (only the one I press, the others are still <Image />). I can do this on a class component, but I want to use a hook
export const MusicVideos = () => {
const [selectedVideo, setVideo] = useState(0);
return (
<Wrapper>
{videos.map(video => (
<div key={video.id}>
<Image src={video.image} hover={video.hover} alt="thumbnail" />
<YouTube link={video.link} />
</div>
))}
</Wrapper/>
);
};
you can bind onClick for your image and setVideo to video.id and compare with video.id to render image or video.
export const MusicVideos = () => {
const [selectedVideo, setVideo] = useState(0);
return (
<Wrapper>
{videos.map(video => (
{selectedVideo !== video.id ?
<Image onClick={() => setVideo(video.id) src={video.image} hover={video.hover} alt="thumbnail" /> :
<YouTube link={video.link} />
))}
</Wrapper/>
);
};
Create a component like this and pass it to the loop;
const YouTubeToggle = (video) => {
const [selectedVideo, setVideo] = useState(0);
return (
<div key={video.id}>
{selectedVideo == 0 &&
<Image src={video.image} onClick={() => setVideo(!selectedVideo)} hover={video.hover} alt="thumbnail" />
}
{selectedVideo != 0 &&
<YouTube link={video.link} />
}
</div>
);
}
export const MusicVideos = () => {
const [selectedVideo, setVideo] = useState(0);
return (
<Wrapper>
{videos.map(video => (
<YouTubeToggle video={video} />
))}
</Wrapper/>
);
};