I'm trying to learn more about working with files for an upcoming project. Is there a way with react-dropzone that I can run a function when onDrop happens to change the contents of the files I'm uploading? For example, if I'm uploading a word doc that says "Hi everybody" how would I change the content to "Hi Dr. Nick"?
I've tried just accessing the data by using the filereader api after before attempting to make the changes. I tried using filereader right after the opening curly bracket of the async function and wasn't able to get it to work.
import React from 'react';
import Dropzone from 'react-dropzone';
import { graphql } from 'react-apollo';
import gql from 'graphql-tag';
const FileUpload = ({
children, disableClick, channelId, mutate, style = {},
}) => (
<Dropzone
style={style}
className="ignore"
onDrop={async ([file]) => {
const response = await mutate({
variables: {
channelId,
file,
},
});
console.log(response);
}}
disableClick={disableClick}
>
{children}
</Dropzone>
);
const createFileMessageMutation = gql`
mutation($channelId: Int!, $file: File) {
createMessage(channelId: $channelId, file: $file)
}
`;
export default graphql(createFileMessageMutation)(FileUpload);
Any thoughts on how to access and modify the contents of the file are greatly appreciated! Thanks.
onDrop={async ([file]) => {
var reader = new FileReader();
reader.onload = function(e) {
var contents = e.target.result;
displayContents(contents);
};
reader.readAsText(file);
}}
What you can do on frontend is to read file content and display it, all manipulations with file content should be done on server side. Push your file using ajax to your server with list of informations you want to change and use for example in nodeJS fs = require('fs')to make file modifications.
Also please visit this post i see that guys provided some solutions for your problem:
Is it possible to write data to file using only JavaScript?
and here is a fidlle taken from above link: http://jsfiddle.net/o4rhg1xe/1/
In Summary, you can read text file content using code i have provided and then use method from link to create Blob object with content you want and such file can be downlaoded by browser, (see fiddle)
Still in my opinion file modifications shoudl be moved to back-end side, ans i cant see no usecase to make them on frontend side.
Related
I'm trying to upload multiple images in React (nextjs) from <input onChange={onChange} type='file' name='file' multiple/>
But which way is more proper to do it? Some hours of googling didn't helped me
This is my approach(that ofc doesn't work, otherwise i would not have to write it):
I stored images' srcs using useState hook:
const [imgsSrc, setImgsSrc] = useState([])
And this is my "input on change handler":
const onChange = (changeEvent: any) => {
for (let file of changeEvent.target.files) {
setTimeout(() => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => { setImgsSrc([...imgsSrc, reader.result]) }
reader.onerror = () => { console.log(reader.error)}
}, 1000)
}
}
My input one more time
<input onChange={onChange} type='file' name='file' multiple/>
And my way to trying to show images to user
{ imgsSrc.map((link) => { <img src={link}/> }) }
But it doesn't show me anything, so i have couple of questions that my nerve cells would be happy to get an answer to
why it doesn't work
does "saving images to public folder in root app directory" a good approach to save images
can i store base64 encode URLs remotely and get it every request, decode it and get an image
please...
You basically have a couple of mistakes that prevent your code from showing anything:
function App() {
const [imgsSrc, setImgsSrc] = useState([]);
const onChange = (e) => {
for (const file of e.target.files) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
setImgsSrc((imgs) => [...imgs, reader.result]);
};
reader.onerror = () => {
console.log(reader.error);
};
}
};
console.log(imgsSrc, imgsSrc.length);
return (
<div>
<input onChange={onChange} type="file" name="file" multiple />
{imgsSrc.map((link) => (
<img src={link} />
))}
</div>
);
}
Since the file reader is asynchronous, you need to tell React to update the state using the most recent state, or you will have bugs, because setState is asynchronous as well, and the loop commands get batched and override the one another.
The fact that you did not have any image output is due to the fact that you are not returning anything from .map.
You can check the fixed version: https://stackblitz.com/edit/react-pgtpnu?file=src%2FApp.js
You can't save files on server if you are using NextJS and you deploy in a serverless environment, you need to use a cloud service, you could use firestore to save base64 strings, or even better, upload the blobs directly to cloudinary, through multer middleware nextJS serverless functions let you write such a function in a few lines.
Saving images in the public directory is not a good approach you should try cloud computing applications such as AWS, Google, or Cloudinary. but I would prefer using Cloudinary because you can store approximately 10GB of images in a free account and also it is easy to integrate with react applications.
How does it work?
1- save your image in Cloudinary through API request then Cloudinary returns the link of the image in response.
2-store the link of the image inside the database
tutorial => upload image cloudinary and react
I have looked at the pdf-lib website and do not see any example to load a PDF using an "input file" on the client side. All examples points to a URL to load a PDF. Is it possible to pass a file object to the function that reads the PDF instead of a URL?
const formPDFBytes = await fetch(url).then(res => res.arrayBuffer())
const pdfDoc= await PDFDocument.load(formPDFBytes );
I think if we can somehow set the file object as an array buffer to formPDFBytes, that may do the trick.
[From OP comments]
The user is the one who has the PDF and loads it via the DOM input file dialog. So nothing here would be sent to the server and the entire PDF parsing operation is done by the client.
According to pdf-lib's code, the PDFDocument.load function accepts in the first argument a string | Uint8Array | ArrayBuffer.
If you want to read a file locally, you can do this:
import fs from 'fs'
const uint8Array = fs.readFileSync('/path/to/myFile.pdf')
const pdfDoc3 = await PDFDocument.load(uint8Array)
if you want to load the file from the <input type="file" /> element,
you need firstly to read the file as ArrayBuffer.
<input type="file" id="file">
//
const file = document.getElementById('file').files[0]
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = () => {
const pdfDoc = await PDFDocument.load(reader.result);
//...
};
I will be dynamically adding elements to my main index.html using .innerHTML += "<p>example</p>"; However I do not want to store the large html-like string in this .js file, but instead import it from another file example.html
example.html:
<p>example</p>
(It is just a snippet of code and not a standalone html file, but I want to keep the .html extension for linting, autocompletion and general readability)
My attempts:
$(...).load('example.html'): did not work as it replaces of contents of ... with this example instead of appending it
import * from example.html: this and other attempts of importing file failed because of MIME error that text/html cannot be imported
I will be perfectly satisfied with a solution of a method that reads .html as text and returns it as a string (preferably not using AJAX or ES6 as I do not feel confident with them). I would then just use the string in .innerHTML += imported_string; and call it a day.
If I correctly understand what you want to do, you can use FileReader to import the content of a file and convert it to text, for example:
function readFile(event) {
var file = event.target.files[0];
var stream = new FileReader();
stream.onload = function(e) {
var fileContent = e.target.result;
alert(fileContent);
}
stream.readAsText(file);
}
document.getElementById('myFile').addEventListener('change', readFile, false);
<input type="file" accept="html" id="myFile">
The file input is for presentation purposes, you can easily adapt this to your needs.
You should also perform the customary checks, which I ommited for brevity purposes.
Create a fetch request to the file that you want to retrieve. This is, in a basic sense, the same way how a browser would request a html file from the server.
The function below sends a request based on what you input as a file. For example, 'example.html'. It then checks if the request was a success and returns the response as a string. The string can then be appended to your innerHTML.
const getFileAsText = async file => {
const response = await fetch(file);
if (!response.ok) {
throw new Error(`Fetching the HTML file went wrong - ${response.statusText}`);
}
return response.text();
};
You can use it like the example below.
getFileAsText('example.html').then(html => {
document.body.innerHTML += html;
});
I am trying to include the option to upload an image in my app (React in the front side and NodeJS in the server one). The issue I am facing is that I am not able to send the file to the server. I saw other questions in this site and tutorials in other websites but I can't find what I'm doing wrong, so I hope you can, please, help me out.
This is part of my React code:
export default class DisplayPicture extends React.Component {
constructor(props) {
super(props);
// etc
}
onImageChange = (event) => {
if (event.target.files && event.target.files[0]) {
const img = event.target.files[0];
const formData = new FormData();
formData.append("image", img);
this.service
.uploadPicture(formData) // API call through a service
.then((backAnswer) => console.log(backAnswer))
.catch((err) => console.log(err));
}
};
render() {
return (
<div>
<p>Please, upload an image</p>
<input type="file" name="image" onChange={this.onImageChange} />
</div>
);
}
}
However, when I take a look at what the service sends to the server, it is an empty object and the server gets obviously the same in req.body and an "undefined" when looking for req.file.
I know the usual thing is to upload files by using a form, but I've already tried and got the same result, so I shared the shorter version.
Thanks in advance!!
My users should be able to upload their logo in my react APP,
Ideally what I want to do is upload the file somewhere IE host it and in the process of doing so, retrieve the URL for it so I can store that URL in the database along with the other settings!
My code for the user to drop the image is quite simple:
this.state = {
files: []
};
<DropZone
onDrop={(files, acceptedFiles, rejectedFiles) => {
this.setState({files: [...this.state.files, ...acceptedFiles]});
}}>
{uploadedFiles}
{fileUpload}
</DropZone>
Then when saving settings i want to call a function which as I said, Uploads the image somewhere and returns that URL so i can then use it to store in a DB.
saveDetails = () => {
// some code here that takes the this.state.files[0]
uploads it somewhere then returns the URL.. THEN i call a DB storage function storing that URL to then be accessed elsewhere?!
}
Is there a common, easy way to do this?
Thanks if you can help!
You want to use axios to post the image data. Use FileReader to read file. Read it as a base 64 image and send it to the server. To read file as a base 64:-
handleDrop(acceptedFiles){
const {onError,onChangeAvatar} = this.props;
const reader = new FileReader();
reader.onabort = ()=>onError("Profile picture reading is aborted!");
reader.onerror = ()=>onError("Error with uploaded file. Try again.");
reader.readAsDataURL(acceptedFiles[0]);
reader.onload = ()=>{
const base64Image = reader.result;
onChangeAvatar(base64Image);
};
}
Now you can use axios to post image:-
onChangeAvatar (base64Image){
Axios.post("/url/to?upload",base64Image).then(response=>console.log(response))
}
save the file and return saved url from server side.