I'm trying to make an api call that allows me to edit a single user. The issue that I'm experiencing is that despite the call being successful (and no errors appearing), the changes are not saving. Can someone kindly guide me as to what I'm doing wrong exactly, please? I feel that I'm missing a function that allows me to save the changes after I make the call, but I'm not entirely sure how to go about this.
Edit user details:
setup() {
const store = vuexStore;
const adminId = router.currentRoute.params.adminId;
/** Edit **/
function editUser(formData) {
formData.adminId = adminId;
editAdminAccount(formData).then(response => {
if (response) {
redirectUserTo(ROUTE_NAMES_ADMIN.ADMIN_ACCOUNTS);
saveUserChanges(formData);
}
})
}
// Action
function editAdminAccount(data) {
return store.dispatch(UPDATE_ADMIN_ACCOUNT, data);
}
getSelectedAdmin(adminId);
const selectedAdmin = computed(() => store.getters.getSelectedAdmin);
function getSelectedAdmin(adminId) {
return store.dispatch(GET_ADMIN_BY_ID, adminId)
}
return {
editUser,
selectedAdmin,
}
}
Actions:
updateAdminAccount({commit}, payload) {
let formData = new FormData()
formData.append('email', payload.email)
formData.append('name', payload.name)
formData.append('password', payload.password);
return apiHandler.put(`user/admin/${payload.adminId}`, formData, apiHandler.getAuthHeader()).then(response => {
return !!apiHandler.isSuccess(response.status);
}).catch(error => {
commit(SET_API_ERROR, error);
});
},
You should maybe check what the api call is returning with some console.logs to be sure of the data that is sent back.
Nevertheless, do not have to work with formdata, you can send your query items directly :
updateAdminAccount({commit}, payload) {
return apiHandler.put(`user/admin/${payload.adminId}`, payload, apiHandler.getAuthHeader())
.then(response => !!apiHandler.isSuccess(response.status))
.catch(error => commit(SET_API_ERROR, error));
}
You also should edit the user directly after the api call in the action, and not from the template. So that the logic is kept at one place :
updateAdminAccount({commit}, payload) {
return apiHandler.put(`user/admin/${payload.adminId}`, payload, apiHandler.getAuthHeader())
.then(response => {
if (!!apiHandler.isSuccess(response.status)) {
commit('UPDATE_ADMIN', payload) // payload or response.data depending if api is returning edited object
}
return !!apiHandler.isSuccess(response.status)
})
.catch(error => commit(SET_API_ERROR, error));
}
Related
I'm trying to update the data with using by axios, and I want to use "id" in request url
like http://localhost/api/firstmemory/1
but return 500 Internal Server Error, because my id does not read prpoerly.
my code
const id = detail.id;
const updateFirstInfo = (e) => {
const upInfo = {
first: first,
date: change,
memo: memo,
}
console.log(id); //1
axios
.put(`api/firstmemory/${id}}`, upInfo)
.then(res => {
console.log("ok");
})
.catch(err => {
alert("err");
});
};
How can I fix it?
%7D is the HTML encoding for character }. If you look carefully you have an extra } where you were using template strings. Remove the extra }:
axios
.put(`api/firstmemory/${id}`, upInfo)
.then(res => {
console.log("ok");
})
.catch(err => {
alert("err");
});
Hopefully that helps!
I'm new to Next Js and functional comoponents. I'm trying to retrieve data from /api/retrieve2
//this is retrieve page
export default function Retrieve() {
const onSubmit = async data => {
const { user } = await axios.post("/api/retrieve2", data);
console.log(user) // user here is undefined
};
return (...);
}
//this is retrieve2, inside the API folder
export default async (req, res) => {
try {
const { data } = await axios.post(myBackendUrl, req.body);
console.log(data) //this is printing the right data - { email: 'casas#gmail.com', code: '123123' }
res.json(data);
} catch (e) {
res.json({ err: e.message || e });
}
};
What am I missing, is this something about Next? About functional components?
You should read about ES6 destructuring
You try to destructure user but the axios respons witch is a object doesnt contain the key user
For data it works because there is a data property in the response
Here are all properties that you can destructure:
{ data, status, statusText, headers, config, request }
You need to get the full URL to make http request to using getInitialProps, here Home is the name of your component
const Home = ({ENDPOINT}) => {
const onSubmit = async data => {
const { data } = await axios.post(`${ENDPOINT}/api/retrieve2`, data);
// consider changing `user` here to `data` since Axios stores response in data object
console.log(data) // should be defined
};
return (...);
}
Home.getInitialProps = ctx => {
const ENDPOINT = getEndpoint(ctx.req);
return { ENDPOINT };
};
// You should store this somewhere you can reuse it
export function getEndpoint(req) {
return !!req
? `${req.headers['x-forwarded-proto']}://${req.headers['x-forwarded-host']}`
: window.location.origin;
}
I am using Django REST Framework and React for a project. I have a API route called /api/account/user/ which accepts both GET and POST requests (RetrieveUpdateAPIView). Now, in my React front end, I have this function in my actions file that I would like to use to update user data:
export const updateUser = (email, name, company, phoneVerified, idVerified) => {
return (dispatch, getState) => {
const token = getState().auth.token
let headers = {
'Content-Type': 'application/json'
}
if (token) {
headers['Authorization'] = `Token ${token}`
}
let body = JSON.stringify({email, name, company, phoneVerified, idVerified})
return fetch('//localhost:8000/api/account/user/', {headers, body, method: 'POST'})
.then(res => {
if (res.status < 500) {
return res.json().then(data => {
return {status: res.status, data}
})
}
else {
console.log('Server error.')
}
})
.then(res => {
console.log(res)
if (res.status === 200) {
dispatch({type: 'USER_UPDATE_SUCCESSFUL', data: res.data})
return res.data
}
else if (res.status === 403 || res.status === 401) {
dispatch({type: 'USER_UPDATE_FAILED', data: res.data})
return res.data
}
else {
dispatch({type: 'USER_UPDATE_FAILED', data: res.data})
return res.data
}
})
}
}
This function works if I pass all parameters (email, name, company, phoneVerified, idVerified), but for example, if I want to only update phoneVerified on a button click event, how do I pass only that parameter? Currently I am doing this:
updateUser: (phoneVerified) => dispatch(auth.updateUser(phoneVerified))
But the server response is This field may not be null. Any help with this will be very much appreciated.
It is not the problem of React, it is how you handle in backend code.
You use HTTP POST method in rest API, by default it uses to create one record
You should implement other HTTP method handling for your endpoint, it is PUT method, but with PUT, you still need to send whole object with updated property to update it (Generally, PUT should use to update the record entirely)
Another HTTP method fit your case much better, it is PATCH method, just like PUT but you can just send the updated property to server with the record id (PATCH should use to update the record partially).
For both case, just SHOULD, not MUST because it is the standard convention of HTTP, it is not restricted. Even you still can use GET method to create record.
It depends on your backend code as well. But the line JSON.stringify({name, ...}) will render {name: null, ...} if name is null. So you're sending null values for all the attributes you're not updating. I would change that code to exclude those attributes altogether.
When building a component that contains 3D print information named a fabmoment, I succeeded using the $route.params filling an author-object and a fabmoment-object with information, like so:
<script>
import SingleSummarized from './SingleSummarized'
// import Comments from '#/components/Comments/Multiple'
export default {
name: 'Single',
data () {
return {
author: null,
fabmoment: null,
tempLicenseID: null,
license: null
}
},
created () {
this.$http.get(`/users/${this.$route.params.author_id}`)
.then(request => { this.author = request.data })
.catch(() => { alert('Something went wrong when trying to retrieve this user!') })
this.$http.get(`/users/${this.$route.params.author_id}/fabmoments/${this.$route.params.fabmoment_id}`)
.then(request => { this.fabmoment = request.data })
.catch(() => { alert('Something went wrong when trying to retrieve the fabmoment attribute data!') })
this.$http.get(`/licenses/${this.fabmoment.license_id`)
.then(request => { this.license = request.data })
.catch(() => { alert('Something went wrong when trying to retrieve the license!') })
},
components: {
SingleSummarized
// Comments
}
}
</script>
In the created part you can see I also am trying to retrieve a license for the fabmoment using this.fabmoment.license_id. It fails on this line.
Is a tempLicenseID an idea? Because I suspect the this.fabmoment is not available yet. And how would I use this to make the request work? Or any other more sensible solution?
You have to make the request for the licenses after you have retrieved the fabmoment object:
this.$http.get(`/users/${this.$route.params.author_id}/fabmoments/${this.$route.params.fabmoment_id}`)
.then(request => { return this.fabmoment = request.data })
.then( fabmoment => this.$http.get(`/licenses/${fabmoment.license_id`)
.then(request => { this.license = request.data })
.catch(() => { alert('Something went wrong when trying to retrieve the fabmoment attribute data!') })
I would like to make an upvote function. I have some posts stored in database with Firebase. I would like to let people upvote (or downvote) for a post.
Here is in my ctrl :
upvote(advice) {
advice.votes = advice.votes + 1;
return this.httpService.updateData(advice)
.subscribe((res:Response) => {
console.log('in subscribe', res);
});
}
And in my service :
updateData (data:any): Observable<any> {
let datas = JSON.stringify(data);
const headers = { 'Authorization': 'secret' };
return this.http.put(this.url + 'data.json', datas, headers)
.catch((e) => {
console.log(e);
})
.finally(() => {
console.log('finally');
})
}
When I check the response in subscribe method inside the controller, I can see the updated value, but my database is now destroyed.
Before :
After :
As you can see, there no more real object after, it replaces everything.
I think I have to change the url or check the post id, but I don't see how to do.
I didn't find anything in the firebase documentation.. So if someone has an idea..
EDIT AFTER #Luke answer
I updated my code like this :
In my ctrl :
upvote(advice) {
advice.votes = advice.votes + 1;
return this.httpService.updateData(advice)
.subscribe((res:Response) => {
console.log(res);
return res;
})
}
And in the service :
getId() {
this.db.list('data').snapshotChanges().map(actions => {
return actions.map(action => ({ key: action.key, ...action.payload.val() }));
}).subscribe(items => {
return items.map(item => item.key);
});
}
updateData (data:any): Observable<any> {
let updateUrl = this.url + '-p1FFxUqY6u1_AZ3ER4eVUt';
let datas = JSON.stringify(data);
const headers = { 'Authorization': 'secret' };
return this.http.put(updateUrl + 'data.json', datas, headers)
.catch((e) => {
console.log(e);
})
.finally(() => {
console.log('finally');
})
}
I can see the vote counter update in the logs and on the front, but not in the database. When I refresh the page the vote come back to 0.
I think I just forgot something..
If you want to add a new item to a location, you should use POST instead of PUT:
this.http.post(this.url + 'data.json', datas, headers)...
If you want to update an existing item by only providing partial data , you should use PATCH instead of PUT. If your HTTP client doesn't support sending PATCH, you can use a GET and specify PATCH in the X-HTTP-Method-Override header.
For full details on all of these, read the Firebase documentation in saving data using the REST API.
To update your data, you need to know the key of that particular item to put in your url; for example: your-firebase-url/.../L3-bvgdsggdgde. Something like this
updateData (data:any): Observable<any> {
updateUrl = this.url + 'L3-bvgdsggdgde';
let datas = JSON.stringify(data);
const headers = { 'Authorization': 'secret' };
return this.http.put(updateUrl + 'data.json', datas, headers)
.catch((e) => {
console.log(e);
})
.finally(() => {
console.log('finally');
})
}
So, how to take the key from Firebase and reuse it? following this Firebase doc when you get data from Firebase
constructor(afDb: AngularFireDatabase) {
afDb.list('items').snapshotChanges().map(actions => {
return actions.map(action => ({ key: action.key, ...action.payload.val() }));
}).subscribe(items => {
return items.map(item => item.key);
});
}
Your object will have a key property, reuse it in your upvote/update method.