react dropzone cannot post with axios - javascript

I'm trying to use react-dropzone in my code and making a POST request to the server with axios, but the POST request always fails and I keep getting the following error:
Uncaught (in promise) Error: Request failed with status code 500
This is my component
constructor(props) {
super(props);
this.state = {
accepted: [],
};
['handleChange', 'handleValidSubmit'].forEach(v => {
this[v] = this[v].bind(this);
});
}
handleValidSubmit(event, values) {
const data = {
accepted: this.state.accepted,
};
console.log(data);
axios({
method: 'post',
url:
'https://oc6tq8iop5.execute-api.ap-southeast-1.amazonaws.com/dev/upload',
data: JSON.stringify(data),
}).then(data => {
console.log(data);
onDrop: accepted => {
accepted.forEach(file => {
req.attach(file.name, file);
});
req.end(callback);
var formData = new FormData();
formData.append('gambar', values.accepted);
console.log(formData);
};
});
}
handleChange(event) {
const { target } = event;
const value = target.type === 'checkbox' ? target.checked : target.value;
const { name } = target;
this.setState({
[name]: value,
});
}
And this is my render methods
<div className="dropzone">
<Dropzone
accept="image/jpeg, image/png, image/jpg"
onDrop={accepted => {
this.setState({ accepted });
}}
maxSize={200000}
multiple={false}
>
<p>Maksimal 2 MB (JPG/PNG)</p>
</Dropzone>
{this.state.accepted.map(f => (
<span key={f.name}>
{f.name} - {f.size} bytes
</span>
))}
</div>

You just need to send header with axios,
const config = { headers: { 'Content-Type': 'multipart/form-data' } };
let fd = new FormData();
values.map((file) => {
fd.append('File[]',file);
});
axios.post(`${ROOT_URL}/ImageUpload`, fd, config)
.then((response) => {
callback(response);
})
.catch(error => {
errorResponse(error);
})

Related

Downloading file onClick is downloading on refresh

In my documents table I'm mapping through some metadata to get a filename and docid that is getting passed to my DocumentDownloadButton:
const DocumentsTableBody = ({ documentMetadata, tableProps }) => {
const { Row, Data } = Table
return (
documentMetadata.map(doc => {
return (
<Row {...tableProps} key={doc.id}>
<Data>{formatDate(doc.creationDate)}</Data>
<Data>
<DocumentNameWrapper>
{doc.name}
</DocumentNameWrapper>
</Data>
<DocumentDownloadButton fileName={doc.name} docId={doc.id} />
</Row>)
})
)
}
From my DocumentDownloadButton I've created a function to download the file taking those two props to download onclick.
The problem is it's downloading the file on refresh even before I've opened the panel which is where the click event happens
const DocumentDownloadButton = ({ docId, fileName }) => {
const { apiFor } = useAxios()
const downloadDocument = (id, file) => {
apiFor('someApi')
.get(`/documents/${id}`, { responseType: 'blob' }, {
headers: {
Accept: 'applicaton/octet-stream'
} })
.then((response) => {
// add loading state
const contentType = response.headers['content-type'] || 'application/octet-stream'
const blob = new Blob([response.data], { type: contentType })
return FileSaver.saveAs(blob, file)
})
.catch((error) => {
console.error(error)
})
}
return (
<>
<DownloadIconContainer onClick={downloadDocument(docId, fileName)}>
<DownloadIconSmall />
</DownloadIconContainer>
</>
)
}
That's because you're invoking the download function immediately rather than passing a reference of the function to the onClick. This should give you the intended behavior:
const DocumentDownloadButton = ({ docId, fileName }) => {
const { apiFor } = useAxios()
const downloadDocument = (id, file) => {
apiFor('someApi')
.get(`/documents/${id}`, { responseType: 'blob' }, {
headers: {
Accept: 'applicaton/octet-stream'
} })
.then((response) => {
// add loading state
const contentType = response.headers['content-type'] || 'application/octet-stream'
const blob = new Blob([response.data], { type: contentType })
return FileSaver.saveAs(blob, file)
})
.catch((error) => {
console.error(error)
})
}
return (
<>
<DownloadIconContainer onClick={() => downloadDocument(docId, fileName)}>
<DownloadIconSmall />
</DownloadIconContainer>
</>
)
}

Network Request Failed with FormData in React Native

I'm trying to post an item to my server. I'm using React Native for my front end and Laravel as my back-end. I have tried it many times but it keeps giving me Network request failed. Though I am trying it on postman and it works fine.
This is my React-Native code::=>
const { name, price, category_id, description, images } = this.state
const formData = new FormData();
formData.append('name', name)
formData.append('price', price)
formData.append('category_id', category_id)
formData.append('description', description)
images.map((image) => {
var fileURI = image.uri;
let filename = fileURI.split('/').pop();
formData.append('images[]', { uri: fileURI, type: image.mime, name: filename });
})
//FETCH
const BASE_URL = BASE_URL
fetch(`http://192.168.8.102:8000/api/items`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
},
body: formData
}).then(response => {
const statusCode = response.status;
const responseJson = response.json();
return Promise.all([statusCode, responseJson]);
})
.then(res => {
const statusCode = res[0];
const responseJson = res[1];
if (statusCode == 200) {
console.log(responseJson)
Alert.alert(
'Post successfull🌟',
'Thank you for posting, there you go 🙌',
[
{ text: 'not now', style: 'cool', },
],
{ cancelable: true },
);
navigation.navigate('DrawerNavigation');
} else if (statusCode == 422) {
Alert.alert('invalid parameters', responseJson.message);
} else {
Alert.alert('account not created', 'something unexpected' + responseJson.message);
}
})
.catch(err => {
Alert.alert('server error', err.message);
}).finally(fin => this.setState({ loading: false }))
This is my Laravel code::=>
$images = $request->file(['images']);
$image_details = array();
foreach ($images as $image ) {
$path = $image->store('public/itemImages');
$exploded_string = explode("/",$path);
$image_details[] = new ItemImage (
[
'name' => $exploded_string[2],
'path' => "storage/{$exploded_string[1]}",
'url' => asset("storage/{$exploded_string[1]}/{$exploded_string[2]}")
]
);
}

React Redux Thunk with callback to another function -- TypeError: Cannot read property 'then' of undefined

I am using react+redux.
I have a modal form with data and images and on success I need to close the modal else display error returned from redux. In the dispatch function I have 1 more callback function to store images to S3. I am returning promise from the redux-thunk but I keep getting "TypeError: Cannot read property 'then' of undefined".
Component
handleSubmit = e => {
e.preventDefault();
if(this.isFieldEmpty()){
this.setState({ message: "All fields are mandatory with at least 1 pic" });
return;
} else {
this.setState({ message: "" });
}
const data = {
name: this.state.name,
description : this.state.description,
points : this.state.points,
attributes : this.state.attributes,
images : this.state.images,
created_by: localStorage.getItem('id'),
}
this.props.createItem(data).then(() => {
this.hideModal();
})
}
const mapDispatchToProps = dispatch => {
return {
createItem: data => {
return dispatch(createItem(data))
},
};
};
Action
const saveItemImages = (images,successcb, failurecb) => {
if(images.length > 0){
const formData = new FormData();
for(var x = 0; x<images.length; x++) {
formData.append('image', images[x])
}
const token = localStorage.getItem('token');
fetch(`${backendUrl}/upload/item-images/`, {
method: "POST",
headers: {
'Authorization': `Bearer ${token}`
},
credentials: 'include',
body: formData
})
.then(res => {
if(res.status === 200){
res.json().then(resData => {
successcb(resData.imagesUrl);
});
}else{
res.json().then(resData => {
failurecb(resData.message);
})
}
})
.catch(err => {
console.log(err);
});
} else {
successcb([]);
}
}
export const createItem = data => { return (dispatch) => {
saveItemImages(data.images, imagesUrl => {
data.images = imagesUrl;
return fetch(`${backendUrl}/admin/createItem`, {
method: 'POST',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json',
'Authorization': `Bearer ${data.token}`
},
credentials: 'include',
body: JSON.stringify(data)
})
.then(res => {
if(res.status === 200){
res.json().then(resData => {
dispatch({
type: ADMIN_CREATE_ITEM_SUCCESS,
payload: resData
})
return true;
});
}else{
console.log("Save failed");
res.json().then(resData => {
dispatch({
type: ADMIN_CREATE_ITEM_FAILED,
payload: {
message: resData.message
}
})
})
}
})
.catch(err => {
dispatch({
type: ADMIN_CREATE_ITEM_FAILED,
payload: {
message: `Internal Error -- ${err}`
}
})
});
}, failedMessage => {
let payload = {responseMessage: failedMessage}
dispatch({
type: ADMIN_CREATE_ITEM_FAILED,
payload: payload
})
});
};
};
Thanks in advance for any help
You should return a Promise to create async flow for the action like this:
export const createItem = data => dispatch => new Promise((resolve, reject) => {
// do something was a success
resolve();
// do something was a fail
reject();
});

How to encode an array and send it via POST request to the backend

I load CSV data in the React.js front-end using FileReader:
import React, { Component } from 'react';
import { CsvToHtmlTable } from 'react-csv-to-table';
import ReactFileReader from 'react-file-reader';
import Button from '#material-ui/core/Button';
const sampleData = `
NUM,WAKE,SIBT,SOBT
1,M,2016-01-01 04:05:00,2016-01-01 14:10:00
2,M,2016-01-01 04:05:00,2016-01-01 14:10:00
3,M,2016-01-01 04:05:00,2016-01-01 14:10:00
`;
class CSVDataTable extends Component {
state={
csvData: sampleData
};
handleFiles = files => {
var reader = new FileReader();
reader.onload = (e) => {
// Use reader.result
this.setState({
csvData: reader.result
})
this.props.setCsvData(reader.result)
}
reader.readAsText(files[0]);
}
render() {
return <div>
<ReactFileReader
multipleFiles={false}
fileTypes={[".csv"]}
handleFiles={this.handleFiles}>
<Button
variant="contained"
color="primary"
>
Load data
</Button>
</ReactFileReader>
<CsvToHtmlTable
data={this.state.csvData || sampleData}
csvDelimiter=","
tableClassName="table table-striped table-hover"
/>
</div>
}
}
export default CSVDataTable;
Then I should send csvData to the backend. What is a proper way to do it?
I tried to send csvData, but then it cannot be properly parsed in the backend. I assume that \n is incorrectly encoded, when csvData arrives to the backend:
fetchData = () => {
const url = "http://localhost:8000/predict?"+
'&wake='+this.state.wake+
'&csvData='+JSON.stringify(this.state.csvData);
fetch(url, {
method: "POST",
dataType: "JSON",
headers: {
"Content-Type": "application/json; charset=utf-8",
}
})
.then((resp) => {
return resp.json()
})
.then((data) => {
this.updateDelay(data.prediction)
})
.catch((error) => {
console.log(error, "catch the hoop")
})
};
How do you suggest me to send csvData? It looks like JSON.stringify(this.state.csvData) does something wrong. Please help me solving this issue. Thanks.
Update:
I tried this:
fetchData = () => {
fetch("http://localhost:8000/predict", {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
wake: this.state.wake,
csvData: this.state.csvData
})
})
.then((resp) => {
return resp.json()
})
.then((data) => {
this.updateDelay(data.prediction)
})
.catch((error) => {
console.log(error, "catch the hoop")
})
};
But then I cannot receive data in Django backend (Python):
print(request.POST)
Output:
<QueryDict: {}>
or:
print(request.POST['csvData'])
Output:
django.utils.datastructures.MultiValueDictKeyError: 'csvData'
Or:
body_unicode = request.body.decode('utf-8')
body = json.loads(body_unicode)
content = body['csvData']
print("content",content)
Output:
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char
0)
in your edit you are setting the content-type to application/json but sending a string in it.
body: JSON.stringify({
wake: this.state.wake,
csvData: this.state.csvData
})
Try changing this to
body: {
wake: this.state.wake,
csvData: this.state.csvData
}

How to post image with fetch?

I just learning react and I create an gallery App, but I have problem with posting picture to API. The problem is that when I click on button ADD there's nothing happend just in console.log I get an error 500.
Here is my component with post request:
class AddPhoto extends Component {
constructor(props) {
super(props);
this.state = {
modal: false,
images: [],
isLoading: false,
error: null,
};
this.toggle = this.toggle.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
toggle() {
this.setState({
modal: !this.state.modal
});
}
handleClick(event) {
event.preventDefault();
this.setState({
modal: !this.state.modal
});
}
handleSubmit(event){
event.preventDefault();
this.setState({ isLoading: true });
let path = this.props.path;
fetch(`http://.../gallery/${path}`, {
method: 'POST',
headers: {'Content-Type':'multipart/form-data'},
body: new FormData(document.getElementById('addPhoto'))
})
.then((response) => response.json())
.then((data)=>{
this.setState({images: data.images, isLoading: false});
this.props.updateImages(data.images);
})
.catch(error => this.setState({ error, isLoading: false}));
}
render() {
return (
<Card className="add">
<div className="link" onClick={this.toggle}>
<CardBody>
<CardTitle>Add picture</CardTitle>
</CardBody>
</div>
<Modal isOpen={this.state.modal} toggle={this.toggle} className={this.props.className}>
<div className="modal-header">
...
</div>
<ModalBody>
<form className="addPhotoForm" id="addPhoto" onSubmit={this.handleSubmit}>
<input type="file" required />
<Button color="success" type="Submit">Add</Button>
</form>
</ModalBody>
</Modal>
</Card>
);
}
}
Do you have any idea what am I doing wrong, why is not working, why I get error 500?
Thanks for helping me.
according to this https://muffinman.io/uploading-files-using-fetch-multipart-form-data it works in different way, at least for me it works as well.
const fileInput = document.querySelector('#your-file-input') ;
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const options = {
method: 'POST',
body: formData,
// If you add this, upload won't work
// headers: {
// 'Content-Type': 'multipart/form-data',
// }
};
fetch('your-upload-url', options);
You should remove the 'Content-Type': 'multipart/form-data' and it started to work.
This is part of my upload component.
Look how i do it, you can modify it, with upload button, if you need.
addFile(event) {
var formData = new FormData();
formData.append("file", event.target.files[0]);
formData.append('name', 'some value user types');
formData.append('description', 'some value user types');
console.log(event.target.files[0]);
fetch(`http://.../gallery/${path}`, {
method: 'POST',
headers: {'Content-Type': 'multipart/form-data'},
body: {event.target.files[0]}
})
.then((response) => response.json())
.then((data) => {
this.setState({images: data.images, isLoading: false});
this.props.updateImages(data.images);
})
.catch(error => this.setState({error, isLoading: false}));
}
render() {
return (
<div>
<form encType="multipart/form-data" action="">
<input id="id-for-upload-file" onChange={this.addFile.bind(this)} type="file"/>
</form>
</div>)
}
This worked fine for me, just try it:
var myHeaders = new Headers();
myHeaders.append("Accept", "application/json");
myHeaders.append("Authorization", "Bearer eyJ0eXAiOiJKV1QiLCJh");
var formdata = new FormData();
formdata.append("image", fileInput.files[0], "Your_iamge_URL");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: formdata,
redirect: 'follow'
};
fetch("YOUR_API_ToCall", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
If you need to send a request with more attributes than the image use:
document.getElementById('inputPhoto').addEventListener('change', (e) => {
let data = new FormData();
const image = e.target.files[0];
data.append('id', 'sendIDHere');
data.append('name', 'sendNameHere');
data.append('image', image);
fetch('/apiToReceiveImage', {
method: 'POST',
body: data
}).then(async (_res) => {
const result = await _res.json();
console.log(result);
});
});
Remember that all attributes should be appended BEFORE the image

Categories