Hello people of Stack Overlflow! I have a problem that I can't solve and I need your help.
My Problem: After I've sent a put request to the server nothing changes. I'm console.logging this inside of my backend console.log(ctx.request.body) and it is the same data as before the put request. Although I'm getting Status Code:200 OK in the network tab.
So, I have a form that should be able to update the data from the API. And inside of my form I have an onSubmit handler:
onSubmit={e => {
e.preventDefault()
onSubmit(id, item)
}}
Here I am calling my function handleSubmit and passing id and item. Id is the id of the object and item is the object itself.
And here's the component that uses the onSubmit:
class DoorSettingsContainer extends Component {
render() {
return (
<div>
<DoorSettingsForm
onSubmit={this.props.updateSettings}
item={this.props.location.state.item}
id={this.props.location.state.item._id}
/>
</div>
)
}
}
function mapStateToProps(state) {
return {
item: state.settings.item
}
}
function mapDispatchToProps(dispatch) {
return {
updateSettings: (id, value) => dispatch(updateSettings(id, value))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(
DoorSettingsContainer
)
And here's my action that handles the put request:
export function updateSettings(id, item) {
return dispatch => {
dispatch({ type: 'SETTINGS_IS_LOADING' })
console.log(dispatch)
console.log('FÖRE', item)
axios
.put(`${settings.hostname}/locks/${id}`, item)
.then(() => {
console.log(item)
dispatch({
type: 'SETTINGS_UPDATED',
payload: {
item,
id
}
})
console.log('EFTER', item) // It's still the same
})
.catch(err => console.log(err))
}
}
And finally, my snippet from my backend:
r.put('/' + key + '/:id', async (ctx, next) => {
console.log(key) // Outputs locks
console.log(ctx.request.body) // Same as before
await ctx.db
.collection(key)
.replaceOne({ _id: objectId(ctx.params.id) }, ctx.request.body)
ctx.body = { _id: ctx.params.id }
})
So my problem is that my put request wont work to 100%. Is it might because I'm using Redux forms? Or is my backend not configured to 100%?
Thanks for all the help!
Related
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));
}
I am using react-select async to load options from a input passed through a API. I get the JSON response that has a list inside it which has a field "FullName" I am attempting to go through the JSON file and store all the field names in an array. The array is then returned as the options.
Inside the JSON there is a list and the list contains the results and for each number there is a FullName
The format of the JSON response:
version:
status:
-status code
-status message
error:
result:
-paginate
list:
-0
--FullName
Below is my class I've shown where I think my issues lies with -----
class ReactSelectExample extends Component {
constructor(props, context) {
super(props, context);
this.state = {
selectedOption: {}
}
}
fetchData = (inputValue, callback) => {
if (!inputValue) {
callback([]);
} else {
setTimeout(() => {
fetch("-----API URL----" + inputValue, {
method: "GET",
})
.then((resp) => {
return resp.json()
})
----------------
.then((data) => {
const tempArray = [];
data.forEach((element) => {
tempArray.push({ label: `${element.fullname}`, value: element.FullName });
});
callback(tempArray);
---------------
})
.catch((error) => {
console.log(error, "catch the hoop")
});
});
}
}
onSearchChange = (selectedOption) => {
if (selectedOption) {
this.setState({
selectedOption
});
}
};
render() {
return ( <div>
<AsyncSelect
value={this.state.selectedOption}
loadOptions={this.fetchData}
placeholder="Admin Name"
onChange={(e) => {
this.onSearchChange(e);
}}
defaultOptions={false}
/>
</div>)
}
}
when I start it up and search all I see is loading but no options with names load in the. the error when I inspect the page I get the error
JSON.parse: unexpected end of data at line 1 of the column 1 of JSON data catch the hoop
this was a CORS policy issue. because the api I was using was external and didn't match my url, the JSON response was not being seen. I switched to calling the api on the backend because there is no CORS for server to server.
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!') })
Basically I am creating a email form with react as view and express for the server. It is working fine.
Instead of redirecting on success I am just wanting to re render the form component on the contact page.
Is there anyway I can access the post request success value from within a react component? maybe calling a fetch method within the contact component that fetchs at the '/contact' end point? will this trigger the app.post() method within my express.js file??
this is my post request on button submit within react:
handleFormSubmit = (name, email, text) => {
axios.post('/contact', {
name: name,
email: email,
text: text
}).then(res => {
this.setState({sent: true})
console.log(this.state);
}).catch(err => {
console.log(err);
})
}
this is my express js post:
server.post('/contact', async (req, res) => {
try {
sendMail(req.body).then(info => console.log(info))
// I am getting a response here just fine
console.log(res)
} catch (error) {
console.log('express line 25: ', error);
}
});
I am using Next.js and nodemailer with GMail
Thanks
Ok sorry guys, problem has nothing to do with any code, its next js setup, i built it and ran and seems to be returning fine!
I don't see your code, but if we use fetch inside a React component, try using componentDidMount:
class Contact extends React.Component {
constructor(props) {
super(props);
this.state = {data: null, isLoading: true};
}
// from the server
componentDidMount() {
fetch('/contact').then( response => response.json()
).then( data => {
this.setState({data, isLoading: false}); // es6 syntax same as this.setState({data: data, isLoading: false})
}).catch( err => {
throw new Error(err);
});
}
render() {
const {data, isLoading} = this.state;
if(isLoading){return (<div>Loading...</div>)} //no data fetched in the initial render
return (
<div>
{data}
</div>
);
}
}
Hopefully that will help you.
Basically I want to show message to user after he successfully submitted form. Like Thanks. Product added. And after few seconds I want this message to disappear.
Currently my code is pretty straightforward and contains 3 action types for AJAX request (ADD_PRODUCT_REQUEST, ADD_PRODUCT_SUCCESS, ADD_PRODUCT_FAILURE).
My component containing form connected to redux via mapDispatchToProps:
import {addProduct} from '../actions/product';
const mapDispatchToProps = dispatch => ({
onSubmit(productName) {
dispatch(addProduct(productName))
}
});
class AddProduct extends React.Component {
addProduct() {
const {onSubmit} = this.props;
onSubmit(this.productNameInput.val);
}
render() {
return (
<form onSubmit={::this.addProduct}>...</form>
)
}
}
And my action creator is also pretty straightforward (pseudocode):
export const addProduct = (name) => dispatch => {
dispatch(addProductRequest())
fetch(...).then(addProductSuccess()).catch(e => addProductFailure(error))
}
How I can using this "standard" react-redux architecture know that AJAX request executed successfully on component side?
I have only 1 idea - add some value to state informing that product was added, like added:true, but I think it's bad idea.
You must return fetch result in actions, then you need to wrap up then and catch statements to catch result of action, something like this:
addProduct() {
this.setState({ error: {}, isLoading: true });
this.props.onSubmit(this.productNameInput.val)
.then(res => this.setState({ isLoading: false, success: { title: "Success!", msg: "Product added!" } }))
.catch(err => this.setState({ isLoading: false, error: err.response.data.error} }));
}
You can bind in future this example handling to your form validation or to your frontend notification system.