I am a React/Spring beginner and I dont know how to make a Fileupload with Primereact.
Their Documentation says following (https://www.primefaces.org/primereact/#/fileupload):
FileUpload requires a url property as the upload target and a name to identify the files at backend.
<FileUpload name="demo" url="./upload"></FileUpload>
But it neither say how do I fetch the data, how I access the "demo" in the backend, nor what kind of reponse I get.
Can anyone help me please? I have already searched the web but did not find anything.
You can do something like this:
<FileUpload name="invoice"
accept="image/*"
customUpload={true}
uploadHandler={invoiceUploadHandler}
mode="basic"
auto={true}
chooseLabel="Upload invoice"/>
const invoiceUploadHandler = ({files}) => {
const [file] = files;
const fileReader = new FileReader();
fileReader.onload = (e) => {
uploadInvoice(e.target.result);
};
fileReader.readAsDataURL(file);
};
Send your request like this
const uploadInvoice = async (invoiceFile) => {
let formData = new FormData();
formData.append('invoiceFile', invoiceFile);
const response = await fetch(`orders/${orderId}/uploadInvoiceFile`,
{
method: 'POST',
body: formData
},
);
};
Important: Do not set any Content-Type header! This will be done automatically.
Related
I'm building this website where users can sometimes upload one audio or one image and sometimes both at the same time to cloudinary. I'm able to upload from the front-end (react.js) one or the other (image or audio) but not both at the same time.
I saw this post that says that it is not possible except if we "write a script and use multi-threads (up to 10 threads) to upload many files at once. " I have no idea what it means in the context of react.js | JavaScript.
My code is the following:
I first call the handleUploadCloudinary with its parameter. The function is being called once the data is ready to be published.
const publishTheEntry = () => {
const {
mainText,
mediaAudio,
mediaImg
} = formData;
if(mediaAudio !== ""){
handleUploadCloudinary("audio");
};
if(mediaImg !== ""){
handleUploadCloudinary("image");
};
};
The handleUploadCloudinary() is the following:
const handleUploadCloudinary = (mediaType) => {
const {
mediaAudio,
mediaImg
} = formData;
const formDataCloudinary = new FormData();
formDataCloudinary.append("upload_preset", my_var_here);
formDataCloudinary.append("timestamp", (Date.now() / 1000) | 0);
if(mediaType === "img"){
formDataCloudinary.append("file", mediaImg);
axios.post(
"https://api.cloudinary.com/v1_1/sismographie-cloud/image/upload",
formDataCloudinary
).then((response) => {
console.log(response);
let url = response.data.secure_url;
setFormData({...formData, mediaImg: url});
})
}else if(mediaType === "audio"){
formDataCloudinary.append("file", mediaAudio);
axios.post(
"https://api.cloudinary.com/v1_1/sismographie-cloud/upload",
formDataCloudinary
).then((response) => {
let url = response.data.secure_url;
setFormData({...formData, mediaAudio: url});
})
}
};
Even if, for when both audio + image are stored into the state, I can console.log() both of the conditions, the state won't bot update the formData with both. One will successfully sate the state with a new cloudinary link while the other one will remain a buffer.
You can loop through your resources list and upload assets one by one, or create new threads at the backend (best practice).
This link is a demo for uploading multiple files using Axios and React:
https://codesandbox.io/s/chunked-client-side-upload-forked-vqx6mp?file=/src/CldCustUploadLgRestApi.js
I currently have a Spring boot API controller method (below) that accepts an object as well as a MultiPart file. I am able to successfully send a POST request via Postman however I am now struggling to make this post request via my front-end ReactJS application using Axios.
#PostMapping(
path = "/upload",
consumes = {
MediaType.APPLICATION_JSON_VALUE,
MediaType.MULTIPART_FORM_DATA_VALUE
},
headers = {
"Content-Type=multipart/form-data"
}
)
public SoundProfile uploadSoundProfile(Authentication auth,
#RequestPart("soundProfileRequest") SoundProfileRequest soundProfileRequest,
#RequestPart("audio_file") MultipartFile audio_file){
return soundProfileService.uploadSoundProfile(auth, soundProfileRequest, audio_file);
}
Postman POST request:
The following is my service method to process the object and file which is responsible for saving the object to a MySQL database and then storing the file in an Amazon S3 bucket.
public SoundProfile uploadSoundProfile(Authentication auth, SoundProfileRequest soundProfileRequest, MultipartFile audio_file) {
if (audio_file.isEmpty()){
throw new IllegalStateException("no audio file received");
}
AppUser current_user = appUserRepository.findByEmail(auth.getName())
.orElseThrow(
() -> new IllegalStateException("User not found")
);
Map<String, String> metadata = new HashMap<>();
metadata.put("Content-Type", audio_file.getContentType());
metadata.put("Content-Length", String.valueOf(audio_file.getSize()));
String soundPath = UUID.randomUUID().toString();
SoundProfile soundProfile = new SoundProfile(
soundPath, // SoundPath = S3 key
soundProfileRequest.getCaseBrand(),
soundProfileRequest.getCaseModel(),
soundProfileRequest.getSwitches(),
soundProfileRequest.getKeycaps(),
soundProfileRequest.getStabilizers(),
soundProfileRequest.getLube(),
soundProfileRequest.getMods(),
current_user
);
// save sound profile to database
soundProfileRepository.save(soundProfile);
String path = String.format("%s/%s", BucketName.KEYBOARD_AUDIO_BUCKET.getBucketName(), current_user.getUserId());
String filename = String.format("%s-%s", audio_file.getOriginalFilename(), soundPath);
// Save audio file to s3 bucket
try {
fileStore.saveAudio(
path,
filename,
Optional.of(metadata),
audio_file.getInputStream()
);
} catch (IOException e) {
throw new IllegalStateException(e);
}
return soundProfile;
}
I would like to send the SoundProfileRequest object and the multipart file separately, meaning I don't want to append the file to a FormData object, but I would still like to send the file along with the form fields in a single post request.
For example in my front-end React Component:
export default function UploadSoundProfile() {
const [caseBrand, setCaseBrand] = useState("");
const [caseModel, setCaseModel] = useState("");
const [switches, setSwitches] = useState("");
const [keycaps, setKeycaps] = useState("");
const [lube, setLube] = useState("");
const [stabilizers, setStabilizers] = useState("");
const [mods, setMods] = useState("");
const [selectedFile, setSelectedFile] = useState("");
const history = useHistory();
const createSoundProfile = (e) => {
e.preventDefault();
const url = "/sound-profile/upload";
const formData = new FormData();
formData.append('caseBrand', caseBrand);
formData.append('caseModel', caseModel);
formData.append('switches', switches);
formData.append('keycaps', keycaps);
formData.append('lube', lube);
formData.append('stabilizers', stabilizers);
formData.append('mods', mods);
**// SHOULD FILE ALSO BE APPENDED TO FORMDATA OBJECT HERE?**
formData.append('audio_file', selectedFile);
const config = {
headers: {
"content-type": "multipart/form-data"
}
}
uploadProfileService.createSoundProfile(url, formData, config);
history.push("/sound-profile/profile");
};
return (
...
)
}
Is there a way to make the POST request with Axios without appending the file to the FormData object while still making a single post request?
I am unsure of how to accomplish this, or if it is possible. I have seen other posts where a file is being .append() to a FormData object, but I am unsure if this will cause an error on the backend.
Thanks for any help in advance!
I am working on react native project connected to firebase. I am =using firebase storage ad=nd trying to upload a file to firebase storage But I get following error.
{code: 400, message: "Bad Request. Could not access bucket quickbuy-a0764.appspot.com","status":"Access_Bucket"}
I tried configuring my permissions but did not work for me.
example of Image Uri I am providing to put() is as follows
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAk and so on
Now what should I do to resolve this issue?
let filename = values.images + Date.now();
let uri = values.images[0];
const uploadTask = storage.ref(`images/${filename}`).put(uri);
uploadTask.on("state_changed", (snapshot) => {
console.log(snapshot);
});
firebase.storage.Reference#put() accepts a Blob, Uint8Array or an ArrayBuffer. Because you are trying to upload a Data URI, which is a string, you need to use [firebase.storage.Reference#putString()`](https://firebase.google.com/docs/reference/js/firebase.storage.Reference#putstring).
To do this for a data URI, you would use:
someStorageRef.putString(uri, firebase.storage.StringFormat.DATA_URL);
Next, based on these lines:
const filename = values.images + Date.now();
let uri = values.images[0];
values.images is an array, which means that filename will end up being something similar to "[object Object],[object Object]1620528961143".
As I covered in this answer on your question yesterday, this is a poor way to generate IDs as it can lead to duplicates & collisions - use a Push ID instead.
const uri = /* ... */;
const rootRef = firebase.database().ref();
const filename = rootRef.push().key;
const uploadTask = storage.ref(`images/${filename}`)
.putString(uri, firebase.storage.StringFormat.DATA_URL);
uploadTask.on("state_changed", (snapshot) => {
console.log(snapshot);
});
Future Use with Version 9 of the SDK
import { getStorage, ref, uploadBytes } from "firebase/storage";
const uploadImage = async (values) => {
const filename = values.images + Date.now();
const uri = values.images[0];
// Create a root reference
const storage = getStorage();
// Create a reference to 'images/$filename.jpg'
const filesImagesRef = ref(storage, 1images/${filename}.jpg);
await uploadBytes(filesImagesRef, uri).then((snapshot) => {
console.log('Uploaded a blob or file!');
});
}
Let us know how this works for you!
I'm playing around with a food recognition api.
I have a component with a local state called ingredients.
In the component, I have an input tag that accepts a file image upload and calls cameraHandler method onChange. The method uses FileReader to convert the image into Base64
Once the FileReader is finished encoding the image, the method calls a redux action fetchIngredientsFromImage to post the base64 image into a route to trigger to trigger an API call (to analyze the ingredients in the image).
The response is sent back to the front end, and used to update store.
So basically, the API call is successful, I get the data I need, and store is updated successfully. Great.
But what I also need to do, is update my local ingredients state. But I don't know how to wait for store to be updated before calling setState.
I've tried componentDidUpdate with if(this.props !== prevProps) methodToUpdateLocalState(), but this doesn't work because for some reason the component won't re-render after store is updated.. Turns out that everything inside componentDidUpdate runs first, and store is updated afterwards. I feel like also isn't necessary (probably).
I also tried .then the awaited readers inside cameraHandler, but .then is undefined.
I'd appreciate any input I could get. Really at a loss here, because I have the data, and I just need to somehow grab it so I can setState.
Component
class RecipesSearch extends Component {
state = {
ingredients: [], //need to update this after store is updated, but how?
};
cameraHandler = async (event) => {
const { fetchIngredientsFromImage } = this.props;
const file = event.target.files[0];
const reader = new FileReader();
await reader.readAsDataURL(file);
reader.onloadend = async () => {
const imgBase = reader.result.replace(/^data:image\/(.*);base64,/, '');
await fetchIngredientsFromImage(imgBase); //.then here is undefined
};
};
render(){
<input
className="form-check-input"
type="file"
name="camera"
accept="image/*"
onChange={this.cameraHandler}
/>
}
Actions
const fetchIngredientsFromImage = (imgBase) => async (dispatch) => {
const { data } = await axios.post(`/api/camera/`, { imgBase });
return dispatch(setIngredientsFromCamera(data)); //successfully updates store
};
as a workaround I made an axios.post call inside cameraHandler. Not proud of it, because I'd like to utilize store and keep it consistent with my other methods, but for the time being it'll do I guess.
cameraHandler = async (event) => {
// const { loadIngredientsFromImage } = this.props;
const file = event.target.files[0];
const reader = new FileReader();
await reader.readAsDataURL(file);
reader.onloadend = async () => {
const imgBase = reader.result.replace(/^data:image\/(.*);base64,/, '');
await axios
.post(`/api/camera/`, { imgBase })
.then((response) => this.setState({ ingredients: response.data }));
};
};
I've got a Next.js app, and I am trying to use FileReader to read the contents of an 'uploaded' file.
My component looks like below:
let fileReader;
let props = {
multiple: false,
onRemove: file => {
const index = fileList.indexOf(file);
const newFileList = fileList.slice();
newFileList.splice(index, 1);
setFileList(newFileList);
},
beforeUpload: file => {
setFileList($ => [file]);
fileReader.readAsText(file);
return false;
},
fileList,
};
useEffect(() => {
fileReader = new FileReader();
fileReader.onload = event => {
setFileData(JSON.parse(event.target.result));
};
setReady(true);
}, []);
My upload form calls props.beforeUpload to pass the file to it, however the issue I have is that fileReader is undefined at this point.
I'm suspecting this is because of what's rendered server side and what's rendered client side, however I'm not sure how to handle this?
I don't know what you suspect is correct but if you really think that server side rendering has broken it, then you could use dynamic import of next and use ssr:false to make it render on the client side only, more info