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.
Related
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 fetching data inside componentDidMount but i get undefined during initial render and again render happens and during that time the state variable gets populated. Now when it is not undefined and after population I want to destructure it and display the data inside my component.
Note: getProjectDetails() makes a GET req to populate the data.
I am getting typer error name of undefined.
constructor(props) {
super(props);
this.state = {
projectDetails: ''
};
}
componentDidMount() {
getProjectDetails(this.props.logged_in_user, this.props.projectId)
.then( res => {
this.setState({projectDetails: res});
})
.catch(err => {
console.log('Error: ' + err);
})
}
//Inside render()
render() {
console.log('Project details from API endpoint: ', this.state.projectDetails.project)
const { projectDetails } = this.state;
console.log('Destructure: ', projectDetails);
const project = this.state.projectDetails.project;
let {
name,
location,
city,
builder_name } = project;
You could check with the following if the state is set:
render() {
if(this.state.projectDetails === ''){
return <div>Loading</div>;
}
else{
return <div>{this.state.projectDetails.project}</div>
}
}
So as long as the state is false, Loading will be returned, if there is a value, then this.state.projectDetails.project gets returned. I hope that helps.
Edit:
The render method will be called twice, before the data is fetched and then, after the state is set. So this would only return the data, if its really set.
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.
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!