Save filelist array from input-element and access files - javascript

I want to be able to select multiple files and send them to my backend but can't figure out how.
In app.js I have a usestate that I send as a prop to my file upload-component.
But after selectig the files I get FileList() with correct number of entries but they are all undefined in my file-state.
If I change the onChange function to :
(e) => setFiles(e.target.files[0])
or any other index I get a correct file. But how do I save the whole file-array directly?
And in the next step when I need to post my files to the backend can I access them by filename or do I need to store them as blobs or byte-arrays to be able to send them in a json-format?
import React from "react";
export const FileUpload = ({ files, setFiles }) => {
return (
<div className="file-upload">
<span className="button">
<i className="material-icons">attachment</i>Choose files
</span>
<input
type="file"
multiple
className="multiple-files"
aria-label="Multiple file upload"
accept="image/*"
onChange={(e) => setFiles(e.target.files)}
/>
</div>
);
};

After some trial and error I came up with this solution:
const fileHandler = e => {
const fileArray = Array.from(e.target.files)
fileArray.map(f => f["id"] = Math.random() * Math.pow(10,16))
setFiles(fileArray)
}

Related

File explorer filtering in react js

I am new to react. A task assigned to create drag and drop component. I followed some blogs to do the task, which only accept image file types. Now the task is when clicked on the upload icon it should open file explorer which should only show image type files. I cannot try to figure out how that would work. Part of my codes which i took from various blogs are:
Drag and drop component:
import React from "react";
import { useDropzone } from "react-dropzone";
import UploadIcon from '#mui/icons-material/Upload';
const Dropzone = ({ onDrop, accept }) => {
// Initializing useDropzone hooks with options
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept
});
/*
useDropzone hooks exposes two functions called getRootProps and getInputProps
and also exposes isDragActive boolean
*/
return (
<div className="dropzone-div" {...getRootProps()}>
<input className="dropzone-input" {...getInputProps()} accept=".gif,.jpg,.jpeg,.png"/>
<div className="text-center">
<UploadIcon fontSize="large"/>
{isDragActive ? (
<p className="dropzone-content"> Release to drop the files here</p>
) : (
<p className="dropzone-content">
<b> Choose a file </b> or drag it here
</p>
)}
</div>
</div>
);
};
export default Dropzone;
In the app.js
import React, { useCallback,useState } from "react";
import './App.css';
import Form from './components/Form';
import DragDrop from './components/DragDrop';
import ImageList from "./components/ImageList";
import cuid from "cuid";
function App() {
const [images, setImages] = useState([]);
const [errorMessage, setErrorMessage] = useState([]);
const onDrop = useCallback(acceptedFiles => {
// Loop through accepted files
acceptedFiles.map(file => {
// Initialize FileReader browser API
if (!file.name.match(/\.(jpg|jpeg|PNG|gif|JPEG|png|JPG|gif)$/)) {
setErrorMessage('please select valid file image');
//this.setState({ invalidImage: 'Please select valid image.' });
return false;
}
if(file.name.match(/\.(jpg|jpeg|PNG|gif|JPEG|png|JPG|gif)$/)){
const reader = new FileReader();
// onload callback gets called after the reader reads the file data
reader.onload = function(e) {
// add the image into the state. Since FileReader reading process is asynchronous, its better to get the latest snapshot state (i.e., prevState) and update it.
setImages(prevState => [
...prevState,
{ id: cuid(), src: e.target.result }
]);
setErrorMessage();
};
// Read the file as Data URL (since we accept only images)
reader.readAsDataURL(file);
}
return file;
});
}, []);
return (
<main className="App">
<h2 className="App">Drag and Drop Example</h2>
<br />
<div className=".dropzone-div">
<DragDrop onDrop={onDrop} accept={ 'image/*'}/>
</div>
<div className="App">
{errorMessage && <span> {errorMessage} </span>}
<ImageList images={images} />
</div>
</main>
);
}
export default App;
Use an input element with the type as file, like so:
<span>
<label for="upload">Upload</label>
<input id="upload" type="file" accept="image/*" />
</span>
You could of course change the label to your liking, such as an upload icon.
This is a native HTML element that comes with the functionality you want, out of the box. It is tempting to code everything by hand, especially if you're a beginner. Just remember to search for native solutions before you try a new functionality, or even better, familiarize yourself with the docs of the language/framework you're using.
By the way, here's the MDN doc for the file input element: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file

react Library UseForm was used. help me see the input image in advance

I made input used {useform} library.
It was appropriate to use many "input".
However, the image preview "Enter" does not work.
I tried to preview the image. I hope you get help.
background-image: url(null); It's printed.
import { useForm, Controller } from 'react-hook-form';
import Select from 'react-select';
const SingleInput = () => {
return(
const [fileUrl, setFileUrl] = useState(null);
const saveFileImage = event => {
const imageFile = event.target.files[0];
const imageUrl = URL.createObjectURL(imageFile);
setFileUrl(imageUrl);
};
<label>
add Media
<input
type="file"
onChange={saveFileImage}
accept="image/*"
{...register('file')}
/>
</label>
<div
style={{
backgroundImage: `url(${fileUrl})`,
}}
/>
)
Thats because your onChange method on input is overrided by onChange from register(). Try to get data from useForm itself or wrap input in Controller, so you can customize this behaviour.

useEffect fetch not retrieving data from local db.json

Im trying to mock a Plant API by using a db.json file (relative path: src\plant-api\db.json), and passing it from the parent component (ItemList) to its child (Item) but its not working because i see no data displayed on screen even tho i can see it in my console.log.
Heres the full code
import React, { useState, useEffect } from "react";
import Item from "./Item";
import Data from "../plant-api/db.json"
const ItemList = () => {
const [plants, setPlants] = useState([]);
useEffect(() => {
fetch(Data)
.then((response) => response.json())
.then((data) => setPlants(data));
}, []);
console.log(Data)
return (
<div className="items">
{plants.map((plant) => {
return (
<div>
<Item data={plant} />
</div>
);
})}
</div>
);
};
export default ItemList;
import React from "react";
import ItemCount from "./ItemCount";
const Item = ({ data }) => {
return (
<div>
<div className="item">
<img src={data.pic} alt="plant-image" />
<h3>{data.name}</h3>
<p>{data.category}</p>
<h4>{data.price}</h4>
<ItemCount stock="10" initial="0" />
</div>
</div>
);
};
export default Item;
directory structure
Any help is needed and appreciated!
maybe you can use the json-server package, so you can create a dummy API,.
an example of using code like the one below in the terminal, make sure the code is run in the db.json file directory.
npx json-server db.json -p2000
later there will be a json server running as an API on port 2000
fetch is used to make network calls, but since you have already have Data imported, you can just set the data in your useEffect hook: setPlants(Data); This should be enough if you're just trying to see how the data renders.
If your data is already in JSON format, you don't need to use a fetch, you can just pop it straight into the const [plants, setPlants] = useState(Data).
If you're trying to simulate a live API, you will have to create a dummy API as Dedi mentioned.

How to insert data with post using react redux?

I am learning react-redux, so I am creating a CRUD app for users using JSON placeholder API, now I am able to display data, delete and edit, but I have a problem with adding data.
Here is a live demo in the sandbox : redux live demo
Now when I click add user button I get the following error.
Cannot read property 'editing' of undefined.
Here is my form component to add a user.
import React, { useState } from 'react'
import {useDispatch} from 'react-redux'
import {addUser, addNewUser } from './redux/acitons/users/Users';
function AddUserForm({ user }) {
const dispatch = useDispatch();
const [name, setName ] = useState(user.name);
const handleSubmit = () =>{
console.log(name)
dispatch(addNewUser( {
...user, name
}));
}
const handleCancel = () => {
console.log(user.id);
dispatch(addUser(user.id))
}
return (
<tr>
<td>{user.id}</td>
<td>
<input
defaultValue={user.name}
onChange={e => setName(e.target.value)}
/>
</td>
<td>
<button type="button" className="btn outline" onClick={handleCancel}>
<i className="material-icons">Cancel</i>
</button>
<button
type="button"
className="btn btn-success btn-link"
onClick={handleSubmit}
>
<i className="material-icons">save</i>
</button>
</td>
</tr>
);
}
export default AddUserForm
What do I need to do to solve the problem?, any help or suggestions will be appreciated, the live demo can be found here in the sandboxredux demo
Looking at your code - it seems like your app is breaking since you are not passing any user-payload object to theaddUser dispatch call(on User.js line 64).
Here's a possible way to solve this:
Passing a new-user payload object with an id 1 higher than the previous user on the list) and then dispatch an editUser for that new id.
const addNewUser = () => {
const usersList = userData.users;
const newUserId = usersList[usersList.length - 1].id + 1;
addUser({
id: newUserId
});
editUser(newUserId);
};
This is a very simplified solution (for example - a better approach would be to give a unique id to each user and index the list on the client not based on the server ids) - but it should give you an idea of how to take this forward.
Well first of all, to temporary handle compile errors put question marks on user?.editing and other places where you use user.id or other parameters.
Other thing, I can see that you are using id for editing and deleting so you should also set id property in your userForm

Use javascript to save file in my project folder

I am VERY new to reactJS and I am trying to create a simple web app that allows me to upload a file and then save that file to my projects directory.
I have tried browserify-fs but its doesn't seem to create the file when I use fs.writeFile
The below code allows me to upload a file but I am struggling to save the file in my project directory
import ReactDOM from 'react-dom';
import Dropzone from 'react-dropzone';
class App extends Component {
onDrop = (acceptedFiles) => {
// Save acceptedFiles in this scripts directory
}
render() {
return (
<Dropzone onDrop={this.onDrop}>
{({getRootProps, getInputProps}) => (
<div {...getRootProps()}>
<input {...getInputProps()} />
Click me to upload a file!
</div>
)}
</Dropzone>
);
}
}
export default App;
ReactDOM.render(
<App />,
document.getElementById('root')
);
browserify-fs stores data in the browser (I'm assuming using local storage, but I can't find a clear statement to that effect).
If you want to store data on the server then you'll need to:
Send the data to the server (using Ajax)
Store that data using server-side code
Use the following function...
function download(content, fileName, contentType) {
var a = document.createElement("a");
var file = new Blob([content], {type: contentType});
a.href = URL.createObjectURL(file);
a.download = fileName;
a.click();
}
...and call as follows...
download('Text to Save to the File', 'TestSave.txt', 'text/plain')

Categories