Please how can i achieve this!
I have a switch button i'll like to use to control boolean value (true/false) in my MongoDB database
isBanned: {
type: Boolean,
default: false,
},
my button
<b-form-checkbox
v-model="post.isBanned"
switch
#change="isBannedUser($event, post._id)"
>
{{ post.isBanned }})
</b-form-checkbox>
What I expect to happen!
If I toggle the switch checkbox from the frontend (Nuxt), I want isbanned to be set to true and change the default false value in database. If I toggle the same checkbox again next time, I want false value to be sent to the backend and change the db value from true to false and vice versa
<script>
export default {
data() {
return {
post: {
isBanned: null,
},
}
},
methods: {
async isBannedUser(e, id) {
const data = {
isBanned: this.post.isBanned,
}
try {
const response = await this.$axios.$patch(`/api/v1/posts/${id}`, data)
} catch (error) {
console.log(error)
}
},
},
}
</script>
and my API
router.patch('/posts/:id', async (req, res) => {
try {
const banned = await Post.findByIdAndUpdate(req.params.id, req.body)
res.status(201).json({ banned })
} catch (err) {
res.json({
message: err.message,
})
}
})
Related
I'm working on a project where I need to send an arrays and an object from the backend (nodejs) through a GET api to the frontend (reactjs) and have both of those be accessible in my reducer. I have never done this, and I'm not sure if I'm going about it the right way. I am currently getting an error saying that totalPages from this line: export const orderMineListReducer = (state = {orders:[], totalPages}, action) => { is not defined. I would really appreciate any help or advice on how to go about sending a GET api with an arrays and an object and receiving an arrays and an object in the reducer. Thank you!
Below, I have included what I have tried to do so far:
Backend:
orderRouter.js
orderRouter.get(
'/mine',
isAuth,
expressAsyncHandler(async (req, res) => {
const page = req.query.page || 1;
const perPage = 20
const orders = await Order.find({ user: req.user._id }).skip(page * perPage).limit(perPage);
const total = await Order.countDocuments();
const totalPages = Math.ceil(total / perPage).toString();
res.status(200).send({
data:
[orders],
totalPages,
});
}),
);
Frontend
orderReducer.js
export const orderMineListReducer = (state = {orders:[], totalPages}, action) => {
switch (action.type) {
case ORDER_MINE_LIST_REQUEST:
return { ...state, loading: true };
case ORDER_MINE_LIST_SUCCESS:
return { ...state, loading: false, orders: action.payload.orders, totalPages: action.payload.totalPages,};
case ORDER_MINE_LIST_FAIL:
return { ...state, loading: false, error: action.payload };
default:
return state;
}
};
orderActions.js
export const listOrderMine = (page) => async (dispatch, getState) => {
dispatch({ type: ORDER_MINE_LIST_REQUEST });
const {
userSignin: { userInfo },
} = getState();
try {
const { data } = await Axios.get(`${BASE_URL}/api/orders/mine?page=${page}`, {
headers: {
Authorization: `Bearer ${userInfo.token}`,
},
});
dispatch({ type: ORDER_MINE_LIST_SUCCESS, payload: data });
} catch (error) {
const message = error.response && error.response.data.message ? error.response.data.message : error.message;
dispatch({ type: ORDER_MINE_LIST_FAIL, payload: message });
}
};
I've also tried just having
res.status(200).send({
orders,
totalPages,
});
instead of res.status(200).send({data: { orders, totalPages,}});
with my reducer like so:
export const orderMineListReducer = (state = { data: {} }, action) => {
switch (action.type) {
case ORDER_MINE_LIST_REQUEST:
return { ...state, loading: true };
case ORDER_MINE_LIST_SUCCESS:
return { ...state, loading: false, data: action.payload,};
case ORDER_MINE_LIST_FAIL:
return { ...state, loading: false, error: action.payload };
default:
return state;
}
};
however in my OrderHistoryScreen.js where I have
const orderMineList = useSelector((state) => state.orderMineList);
const { loading, data, error,} = orderMineList;
const dispatch = useDispatch();
useEffect(() => { dispatch(listOrderMine());
}, [dispatch]);
I am getting undefined for console.log(data.orders) and empty {} for console.log(data).
Your response has this scheme:
{
data: {
orders,
totalPages
}
}
Axios.get will resolve to an object with this schema:
{
data: {
data: {
orders,
totalPages
}
},
status: 200,
statusText: 'OK',
...
}
So you need to change the destructuring or dispatch data.data like this:
dispatch({ type: ORDER_MINE_LIST_SUCCESS, payload: data.data });
Check the Axios documentation on the response schema: https://axios-http.com/docs/res_schema
i am trying to delete a post by its id from the database. I was able to implement the get and post methods in React Native but when i tried to delete it did not work.
here is my delete method in backend:-
router.delete("/:id", (req, res) => {
let { id } = req.params;
Post.findByPk(id).then((post) => {
if (post) {
return post.destroy().then(() => {
res.status(204).send();
});
} else {
res.status(404).send();
}
});
});
in React Native here is the code i am currently using:
const deletePost = () => client.delete("/posts/:id");
here is my button, that when pressed calls the handleDelete function:
<Button title="Delete" onPress={handleDelete}/>
And here is my handle delete so far:
const handleDelete = () => {
Alert.alert("Delete", "Are you sure you want to delete this post?", [
{ text: "Yes", onPress=},
{ text: "No" },
]);
};
Can someone help me finish this? How do i call the deletePost method in my onPress?
Here is my Post Model in backend:
const Post = db.define(
"Post",
{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
title: {
type: Sequelize.STRING,
})
You are not sending id from client. You're passing a string ":id" in that route. Try below code.
const deletePost = (id) => client.delete(`/posts/${id}`);
const handleDelete = (id) => {
Alert.alert("Delete", "Are you sure you want to delete this post?", [
{ text: "Yes", onPress: () => deletePost(id) },
{ text: "No" },
]);
};
Try this way
const handleDelete = () => {
Alert.alert("Delete", "Are you sure you want to delete this post?", [
{ text: "Yes", onPress: () => deletePost() },
{ text: "No" },
]);
};
import React from 'react';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
items: [],
isLoaded: false
};
}
callAPI() {
fetch("http://localhost:4000/api/process/4570")
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result.items
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
this.setState({
isLoaded: false,
error
});
}
)
}
componetDidMount() {
this.callAPI();
}
render() {
var { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
}
else {
return (
<div className="App">
<ul>
{items.map(item => (
<li key={item.id} >
Id: {item.id} | Name: {item.name}
</li>
))}
</ul>
</div>
);
}
}
}
export default App;
console: no error.
react-developer-tool: returns
state=
{
"error": null,
"items": [],
"isLoaded": false
}
I am very new to REACT and APIs. Please guide me through, what mistake i have done here. I am unable to get the API output.
I am always getting "Loading"
The API does return the json:
{"id":"4570","name":"AR_RESUME_CNC_ROUTING"}
you need to set isLoading to true in your callApi function before every thing else, after that you need to set it false when you get the result or when you catch some error.
callAPI() {
this.setState({
isLoading: true,
});
fetch("http://localhost:4000/api/process/4570")
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoading: false,
items: result.items
});
},
(error) => {
this.setState({
isLoading: false,
error
});
}
)
}
a bit explanation about the code, you always want to show loading when your api call begins, thats why we set isLoading in the beginning of the function, then when we get the result (success or failure, does not matter) the loading state should change to false, because we have at least a result!
also as an extra point you can use try {...} catch {...} finally {...} to have better code style like below:
async callApi() {
try {
this.setState({ isLoading: true })
const result = await fetch("http://localhost:4000/api/process/4570")
const data = await result.json()
this.setState({
items: result.items
});
} catch (e) {
this.setState({ error: e })
} finally {
this.setState({ isLoading: false })
}
}
It looks to me it is some sort of scope issue. You are doing:
this.setState({
isLoaded: true,
items: result.items
});
but you are calling it within the function callback of the fetch promise. So, this is probably referencing the internal Promise object.
I recommend you try this:
callAPI() {
const self = this;
fetch("http://localhost:4000/api/process/4570")
.then(res => res.json())
.then(
(result) => {
self.setState({
isLoaded: true,
items: result.items
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
self.setState({
isLoaded: false,
error
});
}
)
}
Re-reference the this, to a new variable (in this case I used self) and try your code there.
Thank you for your response, however the solution which worked for me is as below:
class GetOnlinePosts extends Component {
constructor(props) {
super(props);
this.state = {
error: null,
loading: true,
posts: null,
};
}
async componentDidMount() {
console.log("inside external_json");
const url = "http://localhost:4000/api/process/4570";
const response = await fetch(url);
const data = await response.json();
this.setState({ posts: data, loading: false })
console.log(data);
}
...........
I am getting error 404 that the API cannot be found. The Boolean in API is "auto_delete". I want to change it to true when this is referenced.
I wrote a button to reference a function that would reference this API but OnClick it will not be able to find this API apparently.
I posted first the front end file with constructor/binding, button, and function. I then put API at bottom.
Any input would help.
//FRONT END
This is the front end with button and function button references to
//CONSTRUCTOR AND BINDING FUNCTION
export default class VideoContent extends Component {
constructor(props) {
super(props);
let video = this.props.video;
let user = this.props.user;
this.state = {
fetchDuration: false,
viewed: false,
subscribed:
user &&
user.hasOwnProperty("follows") &&
user.follows.includes(video.author)
};
this.view = this.view.bind(this);
this.report = this.report.bind(this);
this.reportJ= this.reportJ.bind(this);
}
<Button
disabled={user ? !user.userId : true}
onClick={this.reportJ}
style={{ float: "right", backgroundColor: "purple" }}
>
ReportJ
</Button>
//FUNCTION
reportJ() {
const { video, user } = this.props;
confirmAlert({
title: "Confirm Objectionable Content",
message: "You Sure Fool?",
buttons: [
{
label: "Yes",
onClick: () => {
axios
.post(
inDev
? devAPI.concat("reportJ")
: baseAPI.concat("reportJ"),
{
id: video._id,
update: {
auto_delete: true
}
}
)
.then(res => {
this.setState({ changed: true });
})
.catch(error => {
console.log(error);
});
}
},
{
label: "No",
onClick: () => alert("Nevermind")
}
]
});
}
//SERVER JS File with API below
router.post("/reportJ", (req, res) => {
const { id, update } = req.body;
models.Videos.findById(id, function (err, video) {
video.auto_delete = true;
video.save((err, data) => {
if (err)
return res.json({
success: false,
error: err
});
return res.json({
success: true,
data: data
});
});
});
});
I'm having a problem identifying a 'task' in mongoDB from my frontend angular.
This question is the most similar to my question but here it just says req.body.id and doesn't really explain how they got that.
This question involves what I am trying to do: update one document in a collection upon a click. What it does in the frontend isn't important. I just want to change the status text of the Task from "Active" to "Completed" onclick.
First I create a task and stick it in my database collection with this code:
createTask(): void {
const status = "Active";
const taskTree: Task = {
_id: this._id,
author: this.username,
createdBy: this.department,
intendedFor: this.taskFormGroup.value.taskDepartment,
taskName: this.taskFormGroup.value.taskName,
taskDescription: this.taskFormGroup.value.taskDescription,
expectedDuration: this.taskFormGroup.value.expectedDuration,
status: status
};
this.http.post("/api/tasks", taskTree).subscribe(res => {
this.taskData = res;
});
}
When I make this post to the backend, _id is magically filled in!
I'm just not sure how I can pass the id to the put request in nodejs router.put('/:id') when I'm pushing it from the frontend like this:
completeTask(): void {
const status = "Completed";
const taskTree: Task = {
_id: this._id,
author: this.username,
createdBy: this.department,
intendedFor: this.taskFormGroup.value.taskDepartment,
taskName: this.taskFormGroup.value.taskName,
taskDescription: this.taskFormGroup.value.taskDescription,
expectedDuration: this.taskFormGroup.value.expectedDuration,
status: status
};
console.log(taskTree);
this.http.put("/api/tasks/" + taskTree._id, taskTree).subscribe(res => {
this.taskData = res;
console.log(res);
});
}
In the template I have a form that's filled in and the data is immediately outputted to a task 'card' on the same page.
When I send the put request from angular, I get a response in the backend just fine of the response I ask for in task-routes.js:
router.put("/:id", (req, res, next) => {
const taskData = req.body;
console.log(taskData);
const task = new Task({
taskId: taskData._id,
author: taskData.author,
createdBy: taskData.createdBy,
intendedFor: taskData.intendedFor,
taskName: taskData.taskName,
taskDescription: taskData.taskDescription,
expectedDuration: taskData.expectedDuration,
status: taskData.status
})
Task.updateOne(req.params.id, {
$set: task.status
},
{
new: true
},
function(err, updatedTask) {
if (err) throw err;
console.log(updatedTask);
}
)
});
The general response I get for the updated info is:
{
author: 'there's a name here',
createdBy: 'management',
intendedFor: null,
taskName: null,
taskDescription: null,
expectedDuration: null,
status: 'Completed'
}
Now I know _id is created automatically in the database so here when I click create task & it outputs to the 'card', in the console log of task after I save() it on the post request, taskId: undefined comes up. This is all fine and dandy but I have to send a unique identifier from the frontend Task interface so when I send the 'put' request, nodejs gets the same id as was 'post'ed.
I'm quite confused at this point.
So I finally figured this out...In case it helps someone here's what finally worked:
First I moved my update function and (patch instead of put) request to my trigger service:
Trigger Service
tasks: Task[] = [];
updateTask(taskId, data): Observable<Task> {
return this.http.patch<Task>(this.host + "tasks/" + taskId, data);
}
I also created a get request in the trigger service file to find all the documents in a collection:
getTasks() {
return this.http.get<Task[]>(this.host + "tasks");
}
Angular component
Get tasks in ngOnInit to list them when the component loads:
ngOnInit() {
this.triggerService.getTasks().subscribe(
tasks => {
this.tasks = tasks as Task[];
console.log(this.tasks);
},
error => console.error(error)
);
}
Update:
completeTask(taskId, data): any {
this.triggerService.updateTask(taskId, data).subscribe(res => {
console.log(res);
});
}
Angular template (html)
<button mat-button
class="btn btn-lemon"
(click)="completeTask(task._id)"
>Complete Task</button>
// task._id comes from `*ngFor="task of tasks"`, "tasks" being the name of the array
//(or interface array) in your component file. "task" is any name you give it,
//but I think the singular form of your array is the normal practice.
Backend Routes
GET all tasks:
router.get("", (req, res, next) => {
Task.find({})
.then(tasks => {
if (tasks) {
res.status(200).json(tasks);
} else {
res.status(400).json({ message: "all tasks not found" });
}
})
.catch(error => {
response.status(500).json({
message: "Fetching tasks failed",
error: error
});
});
});
Update 1 field in specified document (status from "Active" to "Completed"):
router.patch("/:id", (req, res, next) => {
const status = "Completed";
console.log(req.params.id + " IT'S THE ID ");
Task.updateOne(
{ _id: req.params.id },
{ $set: { status: status } },
{ upsert: true }
)
.then(result => {
if (result.n > 0) {
res.status(200).json({
message: "Update successful!"
});
}
})
.catch(error => {
res.status(500).json({
message: "Failed updating the status.",
error: error
});
});
});
Hope it helps someone!