How to display uploaded file content using context.api? - javascript

i need to display content of the file i choose inside file selector. I have displayed it's name on navbar and when i click on it's name it takes me to the ther blank tab in which i need to have it's content displayed. I need to have only pdf and jpeg file types enabled, not other.
This uploading component is rendered inside one page, which is then rendered inside app component.
Here is my code for uploader:
import React, { useState, useEffect, useContext } from "react";
import { useDropzone } from "react-dropzone";
import Upload from "./pictures/fileUpload.png";
import { fileContext } from "../context/context";
function Uploading() {
const { setFileName } = useContext(fileContext);
const { getRootProps, getInputProps, acceptedFiles } = useDropzone({
noDrag: true,
});
// Logging the selected files to the console. //
console.log(acceptedFiles);
useEffect(() => {
if (acceptedFiles.length === 0) {
console.log("No Uploaded Files. Upload .pdf or .jpeg file !");
} else {
setFileName(acceptedFiles[0].name);
window.localStorage.setItem("fileName", `${acceptedFiles[0].name}`);
}
}, [acceptedFiles]);
return (
<section className="container w-full h-full text-center">
<div {...getRootProps({ className: "dropzone h-full" })}>
<input
{...getInputProps()}
type="file"
/>
<img src={Upload} className="mx-auto cursor-pointer " alt="" />
<label class="text-2xl">Choose Document</label>
</div>
</section>
);
}
export default Uploading;

You can use simple JavaScript for that.
let file = $('#photo')[0].files[0];
let reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function(e){
let blob = new Blob([e.target.result]);
window.URL = window.URL || window.webkitURL;
let blobURL = window.URL.createObjectURL(blob);
let image = new Image();
image.src = blobURL;
image.onload = function() {
//add the image element to the target container
}
}
Sorry for not showing exactly what you wanted. I've showed how you can get image element after file upload and then do stuff with it.

Related

How to show image upload previews with React?

I am building an image upload form using Next.js/React.js, and I want the user to be able to assign a tag to each upload. I also want to show the image preview using 'URL.createObjectURL'. The uploading works fine, but on the upload page where I try to iterate through the list of images to show the preview and show an input box to assign the tag, none of this is showing. I cannot work out why.
The code:
import { useState } from "react";
import Head from 'next/head'
import Layout, { siteTitle } from '../../components/layout'
import Image from 'next/image'
export default function PrivatePage(props) {
const [images, setImages] = useState([])
const [imageURLS, setImageURLS] = useState([])
const [tag, setTag] = useState(null)
const uploadImageToClient = (event) => {
var imageList = images
var urlList = imageURLS
if (event.target.files && event.target.files[0]) {
imageList.push(event.target.files[0]);
urlList.push(URL.createObjectURL(event.target.files[0]))
setImages(imageList);
setImageURLS(urlList);
}
};
const uploadTagToClient = (event) => {
if (event.target.value) {
const i = event.target.value;
setTag(i);
}
};
const uploadToServer = async (event) => {
const body = new FormData()
images.map((file, index) => {
body.append(`file${index}`, file);
});
body.append("tag", tag)
const response = await fetch("/api/file", {
method: "POST",
body
});
};
return (
<Layout home>
<Head>
<title>{siteTitle}</title>
</Head>
<div className="container">
<div className="row">
<h4>Select Images</h4>
<div className="col">
<input type="file" className="btn btn-outline-success-inverse" onChange={uploadImageToClient} />
<input type="file" className="btn btn-outline-success-inverse" onChange={uploadImageToClient} />
</div>
<div className="col">
</div>
<button
className="btn btn-outline-success-inverse"
type="submit"
onClick={uploadToServer}
>
Send to server
</button>
{images.map((file, index) => {
return (
<div class="row ">
<lead>{file.name}</lead>
<input type="text" onChange={uploadTagToClient} />
<image src={imageURLS[index]}/>
</div>)
})}
</div>
</div>
</Layout>
);
}
To clarify, nothing inside images.map is showing when I select images.
The issue happens because you're mutating the arrays you have in state with imageList.push and urlList.push which React doesn't pick up. This means state doesn't actually get updated and a re-render doesn't occur.
To fix it, rather than mutating those state arrays you need to create new ones when updating them.
const uploadImageToClient = (event) => {
if (event.target.files && event.target.files[0]) {
setImages((imageList) => [...imageList, event.target.files[0]]);
setImageURLS((urlList) => [
...urlList,
URL.createObjectURL(event.target.files[0])
]);
}
};
Unrelated to the main issue, you have several minor issues inside the render part of your component, specifically inside images.map.
You need to set a key prop on the outer <div> element;
The <lead> element doesn't exist, and needs to be replaced with a valid element;
The <image> element also doesn't exist, you probably meant <img> or <Image> (from next/image).
You can handle image upload with multiple image preview with following code.
const handleFile = (e) => {
setMessage("");
let file = e.target.files;
for (let i = 0; i < file.length; i++) {
const fileType = file[i]['type'];
const validImageTypes = ['image/gif', 'image/jpeg', 'image/png'];
if (validImageTypes.includes(fileType)) {
setFile([...files,file[i]]);
} else {
setMessage("only images accepted");
}
}
};
Follow this snippet https://bbbootstrap.com/snippets/multiple-image-upload-preview-and-remove-92816546

Add signature image to pdf in React

I have rendered a PDF file in react. I want to add a signature image to it by choosing an image file from the system and place it wherever I place the cursor on a pdf file.
After adding the signature we have to download the pdf along with the signature image on it.
I have used the #react-pdf-viewer library.
I tried but I don't know how to exactly approach this problem.
import React, { useState } from "react";
// Import the main component
import { Viewer } from "#react-pdf-viewer/core"; // install this library
// Plugins
import { defaultLayoutPlugin } from "#react-pdf-viewer/default-layout"; // install this library
// Import the styles
import "#react-pdf-viewer/core/lib/styles/index.css";
import "#react-pdf-viewer/default-layout/lib/styles/index.css";
// Worker
import { Worker } from "#react-pdf-viewer/core"; // install this library
export const App = () => {
// Create new plugin instance
const defaultLayoutPluginInstance = defaultLayoutPlugin();
//for unchange event
const [pdfFile, setPdfFile] = useState(null);
const [pdfFileError, setPdfFileError] = useState("");
//for submit event
const [viewPdf, setViewPdf] = useState(null);
// onchange event
const fileType = ["application/pdf"];
const handlePdfFileChange = (e) => {
let selectedFile = e.target.files[0];
if (selectedFile) {
if (selectedFile && fileType.includes(selectedFile.type)) {
let reader = new FileReader();
reader.readAsDataURL(selectedFile);
reader.onloadend = (e) => {
setPdfFile(e.target.result);
setPdfFileError("");
};
} else {
setPdfFile(null);
setPdfFileError("Please select valid pdf file");
}
} else {
console.log("select your file");
}
};
// form submit
const handlePdfFileSubmit = (e) => {
e.preventDefault();
if (pdfFile !== null) {
setViewPdf(pdfFile);
} else {
setViewPdf(null);
}
};
return (
<div className="container">
<br></br>
<form className="form-group" onSubmit={handlePdfFileSubmit}>
<input
type="file"
className="form-control"
required
onChange={handlePdfFileChange}
/>
{pdfFileError && <div className="error-msg">{pdfFileError}</div>}
<br></br>
<button type="submit" classname="btn btn-success btn-lg">
UPLOAD
</button>
</form>
<br></br>
<h4>View PDF</h4>
<div className="pdf-container">
{/* show pdf */}
{/* show pdf conditionally (if we have one) */}
{viewPdf && (
<>
<Worker workerUrl="https://unpkg.com/pdfjs-dist#2.6.347/build/pdf.worker.min.js">
<Viewer
fileUrl={viewPdf}
plugins={[defaultLayoutPluginInstance]}
/>
</Worker>
</>
)}
{/* if we dont have pdf or viewPdf state is null */}
{!viewPdf && <>No pdf file selected</>}
</div>
</div>
);
};
export default App;
My code for rendering PDF

React: How to setup function to use image from state

I have an imageClassification function within my react component which gets the image to be classified from the img tag using document.getElementById const img = document.getElementById('animal_image');.
The image uploaded via file input updates the state which then gets passed to the the img tag
<img id="animal_image" src={profileImg} alt="a test" />
How can I update the code below so that the classifyImage function gets the image from when the image is upload via file input instead of getting from the img tag. i.e how can i access state within classifyImage function?
I looked at the filereader documentation but still could not figure out.
https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
import React, { Component } from 'react';
import * as automl from '#tensorflow/tfjs-automl';
import '#tensorflow/tfjs-backend-webgl';
import SampleDog from '../images/dogTest.jpg';
import './imageloader.css';
export class ImageLoader extends Component {
state={
profileImg: 'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png'
}
fileSelectedHandle = (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = () =>{
if(reader.readyState === 2){
this.setState({profileImg: reader.result})
}
}
reader.readAsDataURL(file)
}
classifyImage = async () => {
const model = await automl.loadImageClassification('./image_classification_model_v1/model.json')
const img = document.getElementById('animal_image');
const predictions = await model.classify(img)
console.log('predictions', predictions)
}
render() {
const { profileImg } = this.state
return (
<div className="container">
<div className="img-main">
<h2>Image Classification Demo</h2>
<p>Upload an image of a cat or dog to check the prediction score</p>
<div >
<input
type="file"
accept="image/*"
name="image-upload"
id="input"
onChange={this.fileSelectedHandle}
/>
</div>
<div>
<img id="animal_image" src={profileImg} alt="a test" />
</div>
<button
className="img-loader-button"
onClick={() => this.classifyImage()}>Predict Score
</button>
</div>
</div>
)
}
}
export default ImageLoader
To access the state you can just do model.classify(this.state.profileImg). But that’s not gonna work directly cus tensorflow requires an image element or ImageData as input.
So I guess you’ll need to create an image element anyway.
fileSelectedHandle = (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = () =>{
if(reader.readyState === 2) {
const img = document.createElement("img");
img.src = reader.result;
this.setState({ profileImg: img });
}
}
reader.readAsDataURL(file)
}

ReactJs: Refresh img tag after image update where url remains constant but the image from that url changes

In my app, when user changes image, the url of the image remains the same, but the image in the cloud changes.
In other words, suppose the url of the image is URL1, after the user uploads his image, the image retrieved from that url changes, but the URL remains the same.
The problem with this is that React does not detect the change, and so does not refresh the image tag automatically, and I have to refresh the page, in order to see the new image.
Here's my code:
class ProfilePage extends Component {
saveImageUrlInDatabase(profileImageURL) {
const imageData = {
profileImageURL: profileImageURL,
};
this.props.uploadProfilePictureURL(imageData);
}
async updateAvatar(event) {
const imageFile = event.target.files[0];
if (!imageFile) {
return;
}
const imageURL = await this.props.uploadProfileImage(imageFile);
this.saveImageUrlInDatabase(imageURL);
this.setState({
profileImageURL: imageURL,
});
}
render() {
const { profile, loading } = this.props.profile;
if (!profile || loading) {
profileContent = <Spinner />;
} else {
// #BUG: Even though profileImageSrc changes
// It doesn't get update automatically
// It turns out the url does not change
// But, the image does change
let profileImageSrc;
// True if user has updated his image
if (this.state.profileImageURL !== "") {
profileImageSrc = this.state.profileImageURL;
} else {
profileImageSrc = !profile.profileImageURL
? require("assets/img/faces/lofi-girl.png")
: profile.profileImageURL;
}
profileContent = (
<Container>
<div className="owner">
<div className="avatar">
<Label for="avatar-upload">
<img
alt="..."
className="img-circle img-no-padding img-responsive"
src={profileImageSrc}
key={Math.floor(Math.random() * 10)}
style={{
cursor: "pointer",
}}
title="Change profile image"
/>
</Label>
<input
id="avatar-upload"
type="file"
accept="image/*"
style={{ display: "none" }}
onChange={this.updateAvatar}
/>
</div>
</div>
</Container>
);
}
return <div className="section profile-content">{profileContent}</div>;
}
}
Any idea how to solve this?
I was facing the same problem: I was updating the image in a url but the url was the same. The image didn't update because the brower saved the image in caché. What I'm doing is to add a random number to the end of the url. If the component is different, it will update alone; otherwise, you can add a button to update the random number. Something like:
const [random, setRandom] = React.useState(1)
render
<button onClick={()=>setRandom(Math.random())}>
update image
<button/>
<img
className = 'img-miniatura'
src = {url+'?n='+random}
alt='miniatura'
/>
I think you are not declare to React what your state variables are. Normally you need to define the state as described in the docs of React https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class
You would need to do something like this:
constructor(props) {
super(props);
this.state = {profileImageSrc: //the initial url you want}
}
Your component has some issue, try this:
import fallbackImage from "./assets/img/faces/lofi-girl.png";
class ProfilePage extends Component {
constructor(props) {
super(props)
this.state = {
profileImageURL: props.profile.profileImageURL,
}
}
saveImageUrlInDatabase(profileImageURL) {
const imageData = {
profileImageURL: profileImageURL,
};
this.props.uploadProfilePictureURL(imageData);
}
async updateAvatar(event) {
const imageFile = event.target.files[0];
if (!imageFile) {
return;
}
const imageURL = await this.props.uploadProfileImage(imageFile);
this.saveImageUrlInDatabase(imageURL);
this.setState({
profileImageURL: imageURL,
});
}
render() {
const { profile, loading } = this.props.profile;
const { profileImageURL } = this.state;
return (
<div className="section profile-content">
{!profile || loading && <Spinner />}
<Container>
<div className="owner">
<div className="avatar">
<Label for="avatar-upload">
<img
alt="..."
className="img-circle img-no-padding img-responsive"
src={
profileImageURL ?
profileImageURL :
fallbackImage
}
key={Math.floor(Math.random() * 10)}
style={{
cursor: "pointer",
}}
title="Change profile image"
/>
</Label>
<input
id="avatar-upload"
type="file"
accept="image/*"
style={{ display: "none" }}
onChange={this.updateAvatar}
/>
</div>
</div>
</Container>
</div>
)
}
}

Dropzone accepted files filter

I'm trying to create a file upload for STL files. The code below works as in that in the onDrop function the console.log shows an empty array for all other file types and the files if they are of type STL. So it does what it's supposed to do.
However the line
{isDragReject && 'File type not accepted, sorry!'}
always fires, even for stl files. Which certainly would confuse the user.
import React, { useCallback } from 'react';
import Dropzone, { useDropzone } from 'react-dropzone';
const FileDropzone = () => {
const maxSize = 100000000;
const onDrop = useCallback((acceptedFiles) => {
console.log(acceptedFiles);
}, []);
const {
isDragActive,
getRootProps,
getInputProps,
isDragReject,
acceptedFiles,
rejectedFiles,
} = useDropzone({
onDrop,
accept: '.stl',
minSize: 0,
maxSize,
});
const isFileTooLarge =
rejectedFiles &&
rejectedFiles.length > 0 &&
rejectedFiles[0].size > maxSize;
return (
<div className="container text-center mt-5">
<div {...getRootProps()}>
<input {...getInputProps()} />
{!isDragActive && 'Click here or drop a file to upload!'}
{isDragActive && !isDragReject && "Drop it like it's hot!"}
{isDragReject && 'File type not accepted, sorry!'}
{isFileTooLarge && (
<div className="text-danger mt-2">File is too large.</div>
)}
</div>
</div>
);
};
export default FileDropzone;
This is a bug, please see details here: https://github.com/react-dropzone/react-dropzone/issues/888
Solution: Downgrade to previous version of DropZone.

Categories