I have this simple file upload button that I got from antd ant design documentation:
<Upload>
<Button
icon={<UploadOutlined />}
className="upload-btn"
>
Upload a file
</Button>
</Upload>
Every time I upload a file I get this error in the console log:
I don't want it to make a post request when I upload the file, I have a submit button for that.
You can do it by returning false from beforeUpload prop, like this:
<Upload beforeUpload={()=> {
/* update state here */
return false; }}>
<Button icon={<UploadOutlined />}>Select File</Button>
</Upload>
obviously in this manner you have to define a state, and store files in the state to send it to server manually. Here is an example to implement this logic.
Related
I'm using antd <Upload /> component so upload multiple files but the current behaviour is if the user uploads 2 files for the first time and again he uploads 1 more file again so the antd Upload onchange event return 3 files but I only want the file that has been uploaded recently, so any solution for it?
<Upload
onChange={_.debounce(onUploadFiles, 100)}
showUploadList={false}
multiple
>
<Button type="default" shape="round" className="main-upload-btn">
<PlusOutlined /> Add Documents
</Button>
</Upload>
I solved it by passing fileList prop as empty so it will always return newly uploaded files.
<Upload
onChange={_.debounce(onUploadFiles, 100)}
showUploadList={false}
fileList={[]}
multiple
>
<Button type="default" shape="round" className="main-upload-btn">
<PlusOutlined /> Add Documents
</Button>
</Upload>
Hey guys I am using MaterialUI's Upload Button from here: https://material-ui.com/components/buttons/
As you can see below I have copy pasted that button and now I want to upload it to Firebase Firestorage using my hook. By pressing on the button it class changeFoto
<input
accept="image/*"
className={classes.input}
id="contained-button-file"
multiple
type="file"
onChange={(e) => changeFoto(e)}
/>
<label htmlFor="contained-button-file">
<Button className={classes.fotoButton} component="span">
Foto
</Button>
</label>
Here you can see the changeFoto function:
(setFoto is a hook in this case and foto the variable of the useState)
const changeFoto = (e) => {
setFoto(e.target.files[0]);
const pflegeengelRef = storage.child(
"pflegeengel/" + pflegeengelDocumentIDs[selectedIndex]
);
pflegeengelRef.put(foto).then(function (snapshot) {
console.log("Uploaded a file!");
});
};
And indeed something gets uploaded when I go look into the storage there is a file. But it is not my image file it was some weird file format that only had the text "undefined" in it. So that is my problem I guess
This happens because setFoto is an async function. It doesn't update foto immediately - it triggers a render with the new foto as the new value.
When you try to upload foto, it hasn't updated yet. Using put(e.target.files[0]) would solve your problem.
hey guys i am learning react js and I have an update form to update book info. I am using django rest api for endpoints. I have a working form where I can upload files and do all those stuffs but I am not able to show the image which is already there in the template, Here I have a book cover image, which is already there in the database, it should be showing in the front-end and when I change the image, the new one should show, how can I add that feature here, I tried <img src={formData.book_cover} and consoling out this is showing the url, but the image isn't getting displayed.
From the network tab,
The problem I think is
Request URL:http://localhost:3000/media/book/book_sample/pride_in_nat.png
request url since the image gets displayed if the url is localhost:8000 instead of localhost:3000 as it is where the django server backend runs. So, how can I change that?
This is the code.
import React from "react";
function BookInfoForm() {
const initialFormData = Object.freeze({
id: '',
book_cover: '',
book_name: '',
book_summary: '',
});
const [formData, updateFormData] = useState(initialFormData);
const [image, setImage] = useState(null);
const { register, handleSubmit, control, errors } = useForm();
useEffect(() => {
axiosInstance.get('api/books/info/update/').then((res) => {
updateFormData({
...formData,
['book_cover']: res.data.book_cover,
['book_name']: res.data.book_name,
['book_summary']: res.data.book_summary,
});
});
}, [updateFormData]);
const handleChange = (e) => {
if (e.target.name === 'image') {
setImage({
image: e.target.files,
});
// console.log(e.target.files);
}
updateFormData({
...formData,
// Trimming any whitespace
[e.target.name]: e.target.value
});
};
const onSubmit = (data) =>{
let formData = new FormData();
formData.append('user', user.id),
formData.append('book_cover', data.image[0]),
formData.append('book_name', data.book_name),
formData.append('book_summary', data.book_summary),
axiosInstance.put('api/books/info/update/', formData),
}
return (
<>
<form className={classes.form} noValidate onSubmit={handleSubmit(onSubmit)}>
<Grid container spacing={2}>
<Grid item xs={6}>
{/* Show existing book cover and change when new one is uploaded */}
<img src={formData.store_logo} alt="" />
<label htmlFor="book-cover">
<input
accept="image/*"
className={classes.input}
id="book-cover"
onChange={handleChange}
name="image"
type="file"
ref={register}
/>
Book Cover
<IconButton color="primary" component="span">
<PhotoCamera />
</IconButton>
</label>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
id="book_name"
label="Book Name"
name="book_name"
autoComplete="book_name"
value={formData.book_name}
onChange={handleChange}
inputRef={register({maxLength: 30})}
rows={1}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
id="book_summary"
label="Book Summary"
name="book_summary"
autoComplete="book_summary"
value={formData.book_summary}
onChange={handleChange}
inputRef={register({maxLength: 1000})}
multiline
rows={3}
/>
</Grid>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Update
</Button>
</form>
</>
)
}
You might want to take a look at one of my answers on Why React needs webpack-dev-server to run?
As your frontend is running at localhost:3000 and you are providing a relative path to the img tag, the browser is assuming that the image is at localhost:3000.
Whenever your backend host is different than the frontend host, you have to provide a complete URL to the resource i.e., origin(http://localhost:8000) + path to the resource(/book/book_sample/pride_in_nat.png)
As you are storing the path to the resource in your database, just append the origin while giving it to the img tag.
<img src={`http://localhost:8000/${formData.store_logo}`} />
Suggestion
A better approach is to use .env files and load them according to your development or production environment
<img src={`${process.env.IMAGE_STORE_ORIGIN}${formData.store_logo}`} />
And in your .env file or .env.development file, you can add the entry for where your images are stored
In your .env file:
IMAGE_STORE_ORIGIN=http://localhost:8000/
So, when you want to change your backend server origin, you can just change it in one location and it is used inside your entire app instead of changing it manually every time you want to use a new server address.
Take a look at dotenv and dotenv-expand
I hope this should clarify your "why" and "what".
I would advise this as being the best solution and I highly would recommend this even though I have not worked heavily with Django.
I know with Django you can store files in media files as configured in your settings.py, as good and convenient that is I guess but the best solution in my understanding for managing files is dealing with a 3rd party like cloudinary(Very common when working with Node using 3rd party software's to manage files)
So the flow behind:
Make an account on cloudinary(Do not worry it's completely free but can upgrade)
When you want to save a file to DB you first interact with cloudinary with Django.
Once Django is done cloudinary Api will bring back a url of your image.
Then what you only have to do now is now save that link given in your database
Now with your Django Model
In the place where you had image as a "FileField" now you can safely convert to "CharField" or whatever that means text/string in django kind of forgot
Then now in your React app that should work
Cloudinary SDK docs for Django
https://cloudinary.com/documentation/django_integration
You can also look up some example on YouTube for clarity if docs are not clear
https://youtu.be/1T6G7Znrbfg
I am looking here for upload folder in reactjs.I have folder in that doc and docx files are there I just want to upload folder when user click in browse button.where I have to not allowed user for selecting single file. Can someone please give me simple example of folder upload or folder select where user can only select folder not file. Actually I am looking in react-dropzone library but not understanding how can I use this for folder select or upload. If someone can guide me or give me simple example where it showing folder upload example that will be great help.Thanks in Advance.
You can allow folder upload by adding these attributes empty "webkitdirectory directory" into your react-dropzone input.
like this.
<input {...getInputProps()} directory="" webkitdirectory="" type="file" />
by using this user can't select a single file.
its work for me :)
You can allow folder upload by adding theses attributes "webkitdirectory mozdirectory directory" to your input :
<input type="file" webkitdirectory mozdirectory directory />
but you can't disable the user ability to upload only one file.
If you're looking for uploading a folder using d&d I recommend react-uploady:
Its drop-zone supports file and folder drop upload out of the box.
It can even be used to upload child folders recursively:
import Uploady from "#rpldy/uploady";
import UploadDropZone from "#rpldy/upload-drop-zone";
const MyApp = () => (
<Uploady destination={{ url: "my-server.com/upload" }}>
<UploadDropZone
onDragOverClassName="drag-over"
htmlDirContentParams={{ recursive: true }}
>
<span>Drag&Drop File(s) or Folder(s) Here</span>
</UploadDropZone>
</Uploady>
);
Based on Zaif's answer, you can customize a file upload event via the getFilesFromEvent prop, as described in the react-dropzone documentation.
UPDATE:
This is a semplified example taken from the official documentation.
import React from 'react'
import { useDropzone } from 'react-dropzone'
function Plugin(props) {
const {acceptedFiles, getRootProps, getInputProps} = useDropzone({
getFilesFromEvent: event => myCustomFileGetter(event)
})
return (
<section className="container">
<div {...getRootProps({className: 'dropzone'})}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
</section>
)
}
export default Plugin
async function myCustomFileGetter(event) {
const files = []
// Retrieves the files loaded by the drag event or the select event
const fileList = event.dataTransfer ? event.dataTransfer.files : event.target.files
for (var i = 0; i < fileList.length; i++) {
const file = fileList.item(i)
files.push(file)
}
// files returned from this function will be acceptedFiles
return files
}
I'm trying to add simple form element which must not be controlled by Angular.
The goal is to POST file download request, passing authentication token with use of hidden input.
Form code:
<form action="api/admin/codes-csv" method="POST" target="_blank">
<input type="hidden" name="token" value="{{token}}" />
<input class="admin-link" type="submit" value="Download Codes" />
</form>
At server side (aspnet core) I'm returning FileResult with CSV data to download.
This approach worked well with AngularJS but with Angular 5 it does not post to the server (request never happens actually).
If add another <input type="submit" /> right in browser DOM explorer, it works. I've tried to add another submit after page load by the script, but Angular seems to somehow override the behavior and it still doesn't work.
So what I need is seems to stop Angular doing anything with this form and make it act as plain html form.
At first: Are You include FormsModule ?
and try
<button type="submit" class="admin-link">Download Codes</button>
This is not a precise answer, because I was unable to make the form work.
But I was able to make file download with use of native HttpClient & FileSaver plugin.
1) Using my API authenticated via http headers, I'm providing my data as JSON with "text" property containing my CSV: { text: "hello,world,etc" }
2) after getting this result with usual API call, I'm using FileSaver (https://github.com/eligrey/FileSaver.js) to save with proper name, so something like this:
Template:
<a (click)="DownloadCsv()">Download All</a>
Component:
DownloadCsv() {
this.ApiService.Admin.CodesCsv.Post()
.subscribe(result => {
var blob = new Blob([result.text], { type: 'text/csv' });
fs.saveAs(blob, "codes.csv");
});
}
As a result, save dialog with proper file name appears. The ApiService is just a wrapper for native http client, which appends auth headers, handles errors and adds strong-typed definitions.
You use ngNoForm if you want the following:
To import the FormsModule but skip its usage in some forms, for example, to use native HTML5 validation, add the ngNoForm and the tags won't create an NgForm directive.
Source: https://angular.io/api/forms/NgForm#description
Similar answer: https://stackoverflow.com/a/49989002/1918775