How to take value from onChange to Upload Image in React - reactjs

Hello guys I got the following 2 functions:
changeProfileImage=(event)=>{
this.setState({file:event.target.files[0]});
}
and the upload one:
upload(file) {
let formData = new FormData();
const username1 = localStorage.getItem('username')
formData.append("file", file);
return axios({
method: 'post',
url: 'http://localhost:3000/users/addUserImage/'+username1,
data: formData,
headers: {
'Content-Type': `multipart/form-data; boundary=${formData._boundary}`,
},
});
}
Main scope is to update the username1 image with the given one from changeProfileImage function. How can I make my Upload function taking the setState file ?

You can pass the file value as an argument to the upload function when you call it.
code pen: https://codepen.io/akartit/pen/PoaXgQO
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
file: null
};
this.changeProfileImage = this.changeProfileImage.bind(this);
this.upload = this.upload.bind(this);
}
changeProfileImage = (event) => {
// Set the file value in the state
this.setState({ file: event.target.files[0] });
};
upload = (file) => {
let formData = new FormData();
const username1 = localStorage.getItem("username");
formData.append("file", file);
return axios({
method: "post",
url: "https://webhook.site/c62f75b5-32be-4f3f-a6cd-e84f515706f4",
data: formData,
headers: {
"Content-Type": `multipart/form-data; boundary=${formData._boundary}`
}
});
};
render() {
return (
<div>
<input type="file" onChange={this.changeProfileImage} />
<button onClick={() => this.upload(this.state.file)}>Upload</button>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));

Related

How to make file upload in React

i have api like :
static async addTenderAttachment(documentId: number, file: File) {
const request = baseApi.getClient();
const formData = new FormData();
formData.append('attachments', file, file.name);
const options: AxiosRequestConfig = {
url: `/clients/Documents/Requests/${documentId}/Attachments`,
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
};
try {
const response: any = await request(options);
console.log(response);
return { response };
} catch (error) {
return { error };
}
}
also have upload component :
<div className={styles.col}>
<FileInput
label='DocumentFile'
placeholder={
attachments[0]
? attachments[0].name
: ' No file'
}
onChange={onAttachFile}
/>
and have onChange for that component :
const onAttachFile = useCallback((file: File) => {
if (file !== null) {
AttachmentApi.addTenderAttachment(
formValues.id,
file,
).then((resp) => {
console.log('successfully added file ', resp);
getAttachments();
});
}
}, []);
So as you see, i can add file only to existing tender, because only existing ones have documentId,
on createTender window there is no id, only after creating it appears.
Question is, how to make file upload work without id number..?

I am trying to make a post request in a API from React but i get "net::ERR_ABORTED 415"

here is the code and here is the web api that i am connecting to "https://hub.graphistry.com/api-token-auth/", i have try to use axios but id doesn't help with the cors
import React, { Component } from "react";
export default class App extends Component {
async postData() {
try {
let result = await fetch("https://hub.graphistry.com/api-token-auth/", {
method: "post",
mode: "no-cors",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: "orlando",
password: "graphistry1234",
}),
});
console.log(result);
} catch (e) {
console.log(e);
}
}
render() {
return (
<div>
<button onClick={() => this.postData()}>
Press me to post some data
</button>
</div>
);
}
}
In this case, you need to use form-data as bellow:
let formData = new FormData();
formData.append("username", "orlando");
formData.append("password", "graphistry1234");
fetch("https://hub.graphistry.com/api-token-auth/", {
method: "POST",
body: formData
})
fetch() does not expect a JavaScript object at body. curl command and fetch() pattern are not the same.

React - Axios POST form data with files and strings

I had to create Axios POST where the body type is form-data. Some of keys are strings, and some are files. Postman request:
How to add upload buttons to fetch files into state, and how to make Axios request?
Simply trigger a method in onChange event on input of type "file" and send to server with "multipart/form-data" format:
<Input id="file" type="file" onChange={this.uploadFile} />
let formData = new FormData();
/*
Iteate over any file sent over appending the files
to the form data.
*/
for( var i = 0; i < this.files.length; i++ ){
let file = this.files[i];
formData.append('files[' + i + ']', file);
}
/*
Make the request to the POST /select-files URL
*/
axios.post( '/select-files',
formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(function(){
console.log('SUCCESS!!');
})
.catch(function(){
console.log('FAILURE!!');
});
import React, { Component } from 'react';
import axios from "axios";
class FileUpload extends Component {
// API Endpoints
custom_file_upload_url = `YOUR_API_ENDPOINT_SHOULD_GOES_HERE`;
constructor(props) {
super(props);
this.state = {
image_file: null,
image_preview: '',
}
}
// Image Preview Handler
handleImagePreview = (e) => {
let image_as_base64 = URL.createObjectURL(e.target.files[0])
let image_as_files = e.target.files[0];
this.setState({
image_preview: image_as_base64,
image_file: image_as_files,
})
}
// Image/File Submit Handler
handleSubmitFile = () => {
if (this.state.image_file !== null){
let formData = new FormData();
formData.append('customFile', this.state.image_file);
// the image field name should be similar to your api endpoint field name
// in my case here the field name is customFile
axios.post(
this.custom_file_upload_url,
formData,
{
headers: {
"Authorization": "YOUR_API_AUTHORIZATION_KEY_SHOULD_GOES_HERE_IF_HAVE",
"Content-type": "multipart/form-data",
},
}
)
.then(res => {
console.log(`Success` + res.data);
})
.catch(err => {
console.log(err);
})
}
}
// render from here
render() {
return (
<div>
{/* image preview */}
<img src={this.state.image_preview} alt="image_preview"/>
{/* image input field */}
<input
type="file"
onChange={this.handleImagePreview}
/>
<label>Upload file</label>
<input type="submit" onClick={this.handleSubmitFile} value="Submit"/>
</div>
);
}
}
export default FileUpload;

undefined error when trying to set state

I'm trying to upload images and then set the state for each image uploaded.
However, I keep on getting this error when hitting the 'Upload' button:
catch: TypeError: Cannot read property 'setState' of undefined
The error is occurring in this block of code:
.then(function (response) {
//handle success
console.log('then: ', response);
this.setState({
file: e.target.files[0]
});
})
Any help would be appreciated!
Thanks!
Here is the entire component:
import React, { Component } from 'react';
import axios from 'axios';
class ImageUpload extends Component {
constructor(props) {
super(props);
this.state = { file: '', imagePreviewUrl: '' };
}
_handleSubmit(e) {
e.preventDefault();
let fd = new FormData();
fd.append('image', this.state.file);
const config = {
headers: { 'content-type': 'multipart/form-data' }
}
const postData = {
method: 'POST',
credentials: 'include',
body: fd
}
axios({
method: 'post',
url: `/api/gaming/profiles/${this.props.profileId}/files/upload`,
data: postData
})
.then(function (response) {
//handle success
console.log('then: ', response);
this.setState({
file: event.target.files[0]
});
})
.catch(function (response) {
//handle error
console.log('catch: ', response);
});
}
_handleImageChange(e) {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () => {
this.setState({
file: file,
imagePreviewUrl: reader.result
});
}
reader.readAsDataURL(file)
}
render() {
const { questionId } = this.props;
let { imagePreviewUrl } = this.state;
let $imagePreview = null;
if (imagePreviewUrl) {
$imagePreview = (<img src={imagePreviewUrl} />);
} else {
$imagePreview = (<div className="previewText">Please select an Image for Preview</div>);
}
console.log('ImageUpload Render()');
return (
<div className="previewComponent">
<input className="fileInput"
type="file"
onChange={(e) => this._handleImageChange(e)} />
<button className="submitButton"
type="submit"
onClick={(e) => this._handleSubmit(e)}>Upload Image</button>
<div className="imgPreview">
{$imagePreview}
</div>
</div>
);
}
}
export default ImageUpload;
Change your Promise resolver to an arrow function, it'll lexically scope this for you.
Change it to:
.then((response) => {
//handle success
console.log('then: ', response);
this.setState({
file: e.target.files[0]
});
})
In your _handleSubmit(e) define var self = this
then use self.setState instead of this.setState
_handleSubmit(e) {
e.preventDefault();
let fd = new FormData();
fd.append('image', this.state.file);
const config = {
headers: { 'content-type': 'multipart/form-data' }
}
const postData = {
method: 'POST',
credentials: 'include',
body: fd
}
var self = this
axios({
method: 'post',
url: `/api/gaming/profiles/${this.props.profileId}/files/upload`,
data: postData
})
.then(function (response) {
//handle success
console.log('then: ', response);
self.setState({
file: event.target.files[0]
});
})
.catch(function (response) {
//handle error
console.log('catch: ', response);
});
}

React.js, how to send a multipart/form-data to server

We want to send an image file as multipart/form to the backend, we try to use html form to get file and send the file as formData, here are the codes
export default class Task extends React.Component {
uploadAction() {
var data = new FormData();
var imagedata = document.querySelector('input[type="file"]').files[0];
data.append("data", imagedata);
fetch("http://localhost:8910/taskCreationController/createStoryTask", {
mode: 'no-cors',
method: "POST",
headers: {
"Content-Type": "multipart/form-data"
"Accept": "application/json",
"type": "formData"
},
body: data
}).then(function (res) {
if (res.ok) {
alert("Perfect! ");
} else if (res.status == 401) {
alert("Oops! ");
}
}, function (e) {
alert("Error submitting form!");
});
}
render() {
return (
<form encType="multipart/form-data" action="">
<input type="file" name="fileName" defaultValue="fileName"></input>
<input type="button" value="upload" onClick={this.uploadAction.bind(this)}></input>
</form>
)
}
}
The error in backend is "nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found".
After reading this, we tried to set boundary to headers in fetch:
fetch("http://localhost:8910/taskCreationController/createStoryTask", {
mode: 'no-cors',
method: "POST",
headers: {
"Content-Type": "multipart/form-data; boundary=AaB03x" +
"--AaB03x" +
"Content-Disposition: file" +
"Content-Type: png" +
"Content-Transfer-Encoding: binary" +
"...data... " +
"--AaB03x--",
"Accept": "application/json",
"type": "formData"
},
body: data
}).then(function (res) {
if (res.ok) {
alert("Perfect! ");
} else if (res.status == 401) {
alert("Oops! ");
}
}, function (e) {
alert("Error submitting form!");
});
}
This time, the error in backend is: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
Do we add the multipart boundary right? Where should it be?
Maybe we are wrong at first because we don't get the multipart/form-data. How can we get it correctly?
We just try to remove our headers and it works!
fetch("http://localhost:8910/taskCreationController/createStoryTask", {
mode: 'no-cors',
method: "POST",
body: data
}).then(function (res) {
if (res.ok) {
alert("Perfect! ");
} else if (res.status == 401) {
alert("Oops! ");
}
}, function (e) {
alert("Error submitting form!");
});
Here is my solution for image upload with preview through axios.
import React, { Component } from 'react';
import axios from "axios";
React Component Class:
class FileUpload extends Component {
// API Endpoints
custom_file_upload_url = `YOUR_API_ENDPOINT_SHOULD_GOES_HERE`;
constructor(props) {
super(props);
this.state = {
image_file: null,
image_preview: '',
}
}
// Image Preview Handler
handleImagePreview = (e) => {
let image_as_base64 = URL.createObjectURL(e.target.files[0])
let image_as_files = e.target.files[0];
this.setState({
image_preview: image_as_base64,
image_file: image_as_files,
})
}
// Image/File Submit Handler
handleSubmitFile = () => {
if (this.state.image_file !== null){
let formData = new FormData();
formData.append('customFile', this.state.image_file);
// the image field name should be similar to your api endpoint field name
// in my case here the field name is customFile
axios.post(
this.custom_file_upload_url,
formData,
{
headers: {
"Authorization": "YOUR_API_AUTHORIZATION_KEY_SHOULD_GOES_HERE_IF_HAVE",
"Content-type": "multipart/form-data",
},
}
)
.then(res => {
console.log(`Success` + res.data);
})
.catch(err => {
console.log(err);
})
}
}
// render from here
render() {
return (
<div>
{/* image preview */}
<img src={this.state.image_preview} alt="image preview"/>
{/* image input field */}
<input
type="file"
onChange={this.handleImagePreview}
/>
<label>Upload file</label>
<input type="submit" onClick={this.handleSubmitFile} value="Submit"/>
</div>
);
}
}
export default FileUpload;
The file is also available in the event:
e.target.files[0]
(eliminates the need for document.querySelector('input[type="file"]').files[0];)
uploadAction(e) {
const data = new FormData();
const imagedata = e.target.files[0];
data.append('inputname', imagedata);
...
Note:
Use console.log(data.get('inputname')) for debugging, console.log(data) will not display the appended data.
https://muffinman.io/uploading-files-using-fetch-multipart-form-data/ worked best for me. Its using formData.
import React from "react";
import logo from "./logo.svg";
import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";
import Button from "react-bootstrap/Button";
const ReactDOM = require("react-dom");
export default class App extends React.Component {
constructor(props) {
super(props);
this.test = this.test.bind(this);
this.state = {
fileUploadOngoing: false
};
}
test() {
console.log(
"Test this.state.fileUploadOngoing=" + this.state.fileUploadOngoing
);
this.setState({
fileUploadOngoing: true
});
const fileInput = document.querySelector("#fileInput");
const formData = new FormData();
formData.append("file", fileInput.files[0]);
formData.append("test", "StringValueTest");
const options = {
method: "POST",
body: formData
// If you add this, upload won't work
// headers: {
// 'Content-Type': 'multipart/form-data',
// }
};
fetch("http://localhost:5000/ui/upload/file", options);
}
render() {
console.log("this.state.fileUploadOngoing=" + this.state.fileUploadOngoing);
return (
<div>
<input id="fileInput" type="file" name="file" />
<Button onClick={this.test} variant="primary">
Primary
</Button>
{this.state.fileUploadOngoing && (
<div>
<h1> File upload ongoing abc 123</h1>
{console.log(
"Why is it printing this.state.fileUploadOngoing=" +
this.state.fileUploadOngoing
)}
</div>
)}
</div>
);
}
}
React File Upload Component
import { Component } from 'react';
class Upload extends Component {
constructor() {
super();
this.state = {
image: '',
}
}
handleFileChange = e => {
this.setState({
[e.target.name]: e.target.files[0],
})
}
handleSubmit = async e => {
e.preventDefault();
const formData = new FormData();
for (let name in this.state) {
formData.append(name, this.state[name]);
}
await fetch('/api/upload', {
method: 'POST',
body: formData,
});
alert('done');
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
name="image"
type="file"
onChange={this.handleFileChange}>
</input>
<input type="submit"></input>
</form>
)
}
}
export default Upload;
the request was rejected because no multipart boundary was found".
When you send multipart/form-data, the boundary is automatically added to a content-type of a request header. you have to tell the server when the parameter ends with the boundary rule. You had to set the Content-type like this
"Content-Type": `multipart/form-data: boundary=add-random-characters`
This article with guide you: https://roytuts.com/boundary-in-multipart-form-data/
The boundary is included to separate name/value pair in the
multipart/form-data. The boundary parameter acts like a marker for
each pair of name and value in the multipart/form-data. The boundary
parameter is automatically added to the Content-Type in the http
(Hyper Text Transfer Protocol) request header.
For sending multipart/formdata, you need to avoid contentType, since the browser automatically assigns the boundary and Content-Type.
In your case by using fetch, even if you avoid Content-Type it sets to default text/plain. So try with jQuery ajax. which removes the contentType if we set it to false.
This is the working code
var data = new FormData();
var imagedata = document.querySelector('input[type="file"]').files[0];
data.append("data", imagedata);
$.ajax({
method: "POST",
url: fullUrl,
data: data,
dataType: 'json',
cache: false,
processData: false,
contentType: false
}).done((data) => {
//resolve(data);
}).fail((err) => {
//console.log("errorrr for file upload", err);
//reject(err);
});

Resources