Why onClick can't trigger the delete function? - reactjs

What I'm trying to do is when the user clicks the delete button to delete the client, I want to show a modal that asks: Are you sure you want to delete it, yes or no.
The modal is on another component, and I thought to pass the delete function as props, but when I call the function in onClick method in the yes button, it won't delete.
ClientList.js
export default function ListClients() {
const [showModal, setShowModal] = useState();
const [userlist, setUserlist] = useState([]);
function deleteClient() {
const userParams = {
clientName:
clientName,
country: country,
clientid: selectedID,
};
axios
.delete(process.env + "client", {
data: clientParams,
})
.then((response) => {
setClientlist(clientlist.filter((client) => client.id !== clientId));
})
.catch((error) => {
console.log(error);
});
}
return(
<div>
<tbody>
{userlist.length > 0 ? (
userlist.map((userlist) => (
<tr key={userlist.id}>
<td>
<div">
{userlist.id}
</div>
</td>
<td>
<button type="button" onClick= () => setShowModal(true)}>
Delete
</button>
</td
</tr>
</tbody>
<ModalDelete showModal={showModal} setShowModal={setShowModal} onDel={() => deleteClient(clientlist.id)}/>
</div>
);
ModalDelete.js
export default function ModalDelete({ showModal, setShowModal, onDel}) {
return(
<div>
{ showModal ? <Transition.Root show={showModal}>
<div>
<p> Are you sure you want to delete the client?</p>
</div>
<div>
<button type="button" onClick={() => onDel()}>Yes</button>
<button type="button" onClick={() => {setShowModal(false);}} >
Go Back
</button>
</div>
</Transition.Root> : null }
</div>
);
}
Not sure why the client is not deleted

ModalDelete.js
onClick={() => onDel()}
shoud be
onClick={onDel}

Related

Why the function I pass to another component is undefined?

What I'm trying to do is to show a modal(which asks if you want to delete the client, yes or no) when the user deletes a client, and to do that I have passed the function as props to the modal component, when the user clicks yes, the delete function is triggered.
ClientList.js
export default function ListClients() {
const [showModal, setShowModal] = useState();
const [userlist, setUserlist] = useState([]);
function deleteClient() {
const userParams = {
clientName:
clientName,
country: country,
clientid: selectedID,
};
axios
.delete(process.env + "client", {
data: clientParams,
})
.then((response) => {
setClientlist(clientlist.filter((client) => client.id !== clientId));
})
.catch((error) => {
console.log(error);
});
}
return(
<div>
<tbody>
{userlist.length > 0 ? (
userlist.map((userlist) => (
<tr key={userlist.id}>
<td>
<div">
{userlist.id}
</div>
</td>
<td>
<button type="button" onClick= {() =>setShowModal(true) }>
Delete
</button>
</td
</tr>
</tbody>
//the idea is to pass the state for modal to show
<ModalDelete showModal={showModal} setShowModal={setShowModal} onDel={() => deleteClient(clientlist.id)}/>
</div>
);
ModalDelete.js
Modal.js
export default function ModalDelete({ showModal, setShowModal,onDel }) {
console.log(onDel)
return(
<div>
{ showModal ? <Transition.Root show={showModal}>
<div>
<p> Are you sure you want to delete the client?</p>
</div>
<div>
<button type="button" onClick={() => {onDel(); setShowModal(false);}>Yes</button>
<button type="button" onClick={() => {setShowModal(false);}} >
Go Back
</button>
</div>
</Transition.Root> : null }
</div>
);
}
So when I console log the onDel in my console it shows that is undefined. Which means nothing is passed.
Is there a way how to pass the function?
I believe there is no issue from React side but after looking to code seems broken for the delete function, as i can see you are sending a param clientlist.id while calling the onDel, hence your deleteClient function must pass all criteria required so that it should not return undefind. try to fix this code may be your issue will get resolved, one more thing while opening the delete modal you must store this clientListId to a new state so that same can be accessed from the local state, because there is no method defind to store current clicked item from user list

How can I return back to the page after I click yes in a modal?

I have just implemented the modal, when the user deletes a client, the client is deleted.
But the problem is that when I click yes in modal to delete the client, the modal is still open and it won't close.
ClientList.js
export default function ListClients() {
const [showModal, setShowModal] = useState();
const [userlist, setUserlist] = useState([]);
function deleteClient() {
const userParams = {
clientName:
clientName,
country: country,
clientid: selectedID,
};
axios
.delete(process.env + "client", {
data: clientParams,
})
.then((response) => {
setClientlist(clientlist.filter((client) => client.id !== clientId));
})
.catch((error) => {
console.log(error);
});
// const openModal = () => {
// setShowModal(prev => !prev);
// };
}
return(
<div>
<tbody>
{userlist.length > 0 ? (
userlist.map((userlist) => (
<tr key={userlist.id}>
<td>
<div">
{userlist.id}
</div>
</td>
<td>
<button type="button" onClick={() => {setSelectedID(clientlist.id); setShowModal(true)}}>
Delete
</button>
</td
</tr>
</tbody>
//the idea is to pass the state for modal to show
<ModalDelete showModal={showModal} setShowModal={setShowModal} onDel={deleteClient(clientlist.id)}/>
</div>
);
ModalDelete.js
export default function ModalDelete({ showModal, setShowModal,onDel }) {
return(
<div>
{ showModal ? <Transition.Root show={showModal}>
<div>
<p> Are you sure you want to delete the client?</p>
</div>
<div>
<button type="button" onClick={onDel}>Yes</button>
<button type="button" onClick={() => {setShowModal(false);}} >
Go Back
</button>
</div>
</Transition.Root> : null }
</div>
);
}
How can I not show the modal after the user clicks yes to delete the client?
Calling setShowModal(false) after onDel:
<button type="button" onClick={() => {
onDel();
setShowModal(false);
}}>Yes</button>
And rewrite ModalDelete in this way:
<ModalDelete showModal={showModal} setShowModal={setShowModal} onDel={() => deleteClient(clientlist.id)}/>

Item in array getting deleted from top only

I have an array off which I would like to delete elements upon clicking the delete button. However, the problem with this is that only the data at the gets deleted no matter where I click leaving the data at that index intact. I would like to know what I can do to ensure this works normally. Below is my code:
import { useEffect, useState } from "react";
const Task = () => {
const [todos, setTodos] = useState([]);
useEffect(() => {
fetch('http://jsonplaceholder.typicode.com/todos')
.then(res => res.json())
.then(data => {
setTodos(data)
})
}, []);
//Using splice
// const deleteTodo = (index) => {
// const temp = [...todos];
// temp.splice(index, 1);
// setTodos(temp);
// console.log(index);
// // console.log(`newData : ${arr} || newLength : ${arr.length}`);
// console.log(`newLength : ${todos.length}`);
// }
//Using Filter
const deleteTodo = (index) => {
const newTodo = todos.filter(todo => todo.id !== index);
setTodos(newTodo);
console.log(`newLength : ${todos.length}`);
}
return (
<div className='container'>
<table className='table'>
<tbody>
{todos.map((key, value) => (
<tr key={key.id}>
<td>{todos[value].id}</td>
<td>{todos[value].title}</td>
<td>{`${todos[value].completed}`}</td>
<td>
<button className='btn btn-danger ' onClick={() => deleteTodo(key)}> Delete </button>
</td>
</tr>
))}
</tbody>
</table>
<button className='btn btn-primary'>Add Task</button>
</div>
);
}
export default Task;
I have tried both the splice and the filter methods.
The splice method deletes data only off the top irrespective of the data I delete whereas the filter method doesn't do anything at all as shown on the snippet below. The length remains the same even after clicking the delete button.
In .map() method the first argument - current array item, the second - index. You pass the current array item to your deleteTodo func, instead of passing id (deleteTodo(key.id)).
It should be like this:
const deleteTodo = (index) => {
const newTodo = todos.filter(todo => todo.id !== index);
setTodos(newTodo);
console.log(`newLength : ${todos.length}`);
}
return (
<div className='container'>
<table className='table'>
<tbody>
{todos.map((key, value) => (
<tr key={key.id}>
<td>{todos[value].id}</td>
<td>{todos[value].title}</td>
<td>{`${todos[value].completed}`}</td>
<td>
<button className='btn btn-danger ' onClick={() => deleteTodo(key.id)}> Delete </button>
</td>
</tr>
))}
</tbody>
</table>
<button className='btn btn-primary'>Add Task</button>
</div>
);
Also you don't need to do todos[value] as you already have a current item.
You could use this:
todos.map((item, index) => (<>
<td>{item.id}</td>
<td>{item.title}</td>
</>)

useEffect call different API onClick

I am working with useEffect and want to figure out how to call a different API when an onClick event happens. When my page loads the following is run:
useEffect(() => {
if (userData.user) {
axios
.get(`http://localhost:5000/reviews/reviews?email=${userData.user.email}`, userData)
.then((response) => {
console.log(response)
setReview(response.data)
});
}
}, [userData]);
however when a user selects an onClick event on the webpage, I want a different API to be called and for the data from the original request to disappear. Here is the second request I want to send:
axios
.get(`http://localhost:5000/reviews/reviews?reviewNumber=1`)
.then(response => {
console.log(response)
setallreviews(response.data)
})
Adding the page code here as requested:
return(
<div>
{userData.user ? (
<div>
<div>
<FeedbackNav />
</div>
<div>
<div>
{filterMode ? (
<div onClick={() => setFilterMode(false)}>
<h1 className='testing123'>My reviews and feedback</h1>
<p className='testing1234'>Reviews are reviews that you have provided on another project</p>
<p className='testing1234'>Feedback is feedback that others have provided on your own project</p>
<button className='rectangle' onClick={() => setFilterMode(false)}>
<img className='filterImage' src={Filter} />Filter
</button>
<ul className='filteroptions'>
<p className='allreviewsfeedback' onClick={() => {
setFilterMode();
getReviews();
}}>My reviews</p>
<p className='myfeedback' onClick={() => {
setFilterMode();
}}>My feedback</p>
</ul>
</div>
) : (
<div>
<h1 className='testing123'>My reviews and feedback</h1>
<p className='testing1234'>Reviews are reviews that you have provided on another project</p>
<p className='testing1234'>Feedback is feedback that others have provided on your own project</p>
<button className='rectangle' onClick={() => setFilterMode(true)}>
<img className='filterImage' src={Filter}/>
Filter
</button>
</div>
)}
</div>
<div className='testing1234'>
{allreviews.map(allreviews => (
<p key={allreviews._id}>{allreviews.review}</p>
))}
</div>
<div className='testing1234'>
{review.map(review => (
<p key={review._id}>{review.review}</p>
))}
</div>
</div>
</div>
) : (
<div>
<Landing />
</div>
)}
</div>
)
}
What is the best way to do this? Thank you!
You can do something like this:
const [clicked, setClicked] = useState(false);
const handleClick = () => {
setClicked(true);
};
useEffect(() => {
if (clicked) {
axios
.get(`http://localhost:5000/reviews/reviews?reviewNumber=1`)
.then(response => {
console.log(response)
setallreviews(response.data)
setReview(null);
});
} else if (userData.user) {
axios
.get(`http://localhost:5000/reviews/reviews?email=${userData.user.email}`, userData)
.then((response) => {
console.log(response)
setReview(response.data)
});
}
}, [userData]);
return (
<div>
some text...
<button onClick={handleClick}>Click!</button>
</div>
);
Listen to search params and call axios.get if search params changed.
const { search } = useLocation(); // import { useLocation } from 'react-router-dom';
useEffect(() => {
if (!search) return;
axios.get(`http://localhost:5000/reviews/reviews${search}`).then();
}, [search]);

How to pass parameter to a function on onClick event in ReactJS

class UserList extends Component{
constructor() {
super();
this.state = {
list: [],
};
}
componentDidMount() {
this.getList();
}
getList(){
axios
.get('/getList')
.then(response => {
if(response.data.status == 'success'){
this.setState({
list: response.data.list,
});
console.log(response);
}
})
.catch(error => {
if (error.response) {
console.log(error.response);
}
});
}
{/*I want to call this function with userid when remove button is pressed */}
deleteUser(){
}
render(){
if(!localStorage.getItem('name')){
return( <Redirect to={'/login'} /> )
}
return (
<div id="wrapper">
<table className="table table-hover">
<thead>
<tr>
<th>#No</th>
<th>#Name</th>
<th>#Delete</th>
</tr>
</thead>
<tbody>
{
this.state.list.map(function(item, i){
return <React.Fragment>
<tr key={i}>
<td>{item.id}</td>{/* **This is user id** */}
<td>{item.name}</td>
<td>
<button type="button" onClick="deleteUser(item.id)" className="btn btn-danger btn-sm">Remove</button>
</td>
</tr>
</React.Fragment>
})
}
</tbody>
</table>
</div>
)
}
}
export default UserList;
I am new to ReactJS. I am trying to pass userid to function with onClick event to Remove button. But unable to send userid and it shows error. How can I do it. Can anybody help me with this.
I am trying to pass userid to function with onClick event to Remove button. But unable to send userid and it shows error. How can I do it. Can anybody help me with this.
I am trying to pass userid to function with onClick event to Remove button. But unable to send userid and it shows error. How can I do it. Can anybody help me with this.
Your handler is not bound. You need to declare it like this:
onClick={() => this.deleteUser(item.id)}
So change it to:
{this.state.list.map((item, i) => {
return <React.Fragment>
<tr key={i}>
<td>{item.id}</td>{/* **This is user id** */}
<td>{item.name}</td>
<td>
<button
type="button"
onClick={() => this.deleteUser("asd")}
className="btn btn-danger btn-sm"
>
Remove
</button>
</td>
</tr>
</React.Fragment>
})}
And your handler:
deleteUser = (id) => {
console.log(id)
}
You can call a function in ReactJS with:
<button type="button" onClick={() => deleteUser(item.id)}>...</button>
The function call is an expression and hence you need to use {} instead of double quotes.
Another essential ingredient for this to work is the context in which it is called. Currently it is inside a function, like so:
.map(function(item, i) {
})
The function here owns the usage of this inside it and hence this.deleteUser will not work. To get this to work, you need to convert function to an arrow function which has no this binding.
.map((item, i) => {
return (
<button type="button" onClick={() => deleteUser(item.id)}>...</button>
)
})

Resources