I was following one of the tutorials with React js when this isuue came up. I am using Cloudinary React SDK (React image and video upload). I am using their Upload Widget. But when I press the button to open the widget it gives me this error - 'TypeError: Cannot read property 'createUploadWidget' of undefined'
Here's the script src - <script src="https://widget.cloudinary.com/v2.0/global/all.js" type="text/javascript" ></script>
Here's the code of App.js
import React, { useState } from "react";
import "./App.css";
export default function App() {
const [imageUrl, setimageUrl] = useState(null);
const [imageAlt, setimageAlt] = useState(null);
const handleImageUpload = () => {
const { files } = document.querySelector('input[type="file"]');
const imageFile = document.querySelector('input[type="file"]');
// destructure the files array from the resulting object
const filesa = imageFile.files;
// log the result to the console
console.log("Image file", filesa[0]);
const formData = new FormData();
formData.append("file", files[0]);
// replace this with your upload preset name
formData.append("upload_preset", "xxxxxxx");
const options = {
method: "POST",
body: formData,
};
// replace cloudname with your Cloudinary cloud_name
return fetch(
"https://api.Cloudinary.com/v1_1/xxxxxx/image/upload",
options
)
.then((res) => res.json())
.then((res) => {
setimageUrl(res.secure_url);
setimageAlt(`An image of ${res.original_filename}`);
})
.catch((err) => console.log(err));
};
const openWidget = () => {
// create the widget
const widget = window.Cloudinary.createUploadWidget(
{
cloudName: "xxxxxx",
uploadPreset: "xxxxx",
},
(error, result) => {
if (result.event === "success") {
setimageUrl(result.info.secure_url);
setimageAlt(`An image of ${result.info.original_filename}`);
}
}
);
widget.open(); // open up the widget after creation
};
return (
<div className="app">
<section className="left-side">
<form>
<div className="form-group">
<input type="file" />
</div>
<button type="button" className="btn" onClick={handleImageUpload}>
Submit
</button>
<button type="button" className="btn widget-btn" onClick={openWidget}>
Upload Via Widget
</button>
</form>
</section>
<section className="right-side">
<p>The resulting image will be displayed here</p>
{imageUrl && (
<img src={imageUrl} alt={imageAlt} className="displayed-image" />
)}
</section>
</div>
);
}
Any help is greatly appreciated !
Cloudinary should be referenced in a lowercase -
...
const widget = window.cloudinary.createUploadWidget(
...
Related
I am using Nextjs to build a full-stack application I working on the admin cms and I try to upload a file like an image or etc. I do this from this post with a little difference in UI.
The upload function is good and everything is good with no errors and no problems. But I need to show upload progress or a percentage to the user but every topic I read on every site doesn't help me. how to do this?
front-end code:
import Image from "next/image";
import { useRef, useState } from "react";
import Theme from "../components/layouts/theme";
const Home = (props) => {
const choosenFile = useRef();
const [staticImage, setStaticImage] = useState();
const handleForm = async (event) => {
event.preventDefault();
const myFile = choosenFile.current.files;
const fileUrl = URL.createObjectURL(myFile[0]);
const data = new FormData();
data.append("file", myFile[0]);
try {
const response = await console.log("status", response);
if (!response.ok) {
throw new Error("Something went wrong!");
}
const responseData = await response.json();
console.log("response", responseData);
} catch (err) {
console.log("upload", err);
}
};
const setImage = (param) => {
setStaticImage(URL.createObjectURL(param));
};
return (
<div className="container">
{staticImage && (
<>
<div
className="thumbnail"
style={{ width: "100px", height: "100px" }}
>
<Image
src={staticImage}
width={300}
height={300}
layout="responsive"
/>
</div>
<p>The upload percentage shows here: <span className="text-danger">10%</span></p>
</>
)}
<div className="row justify-content-center">
<div className="col-10 p-5">
<form onSubmit={handleForm}>
<div className="input-group mb-3">
<input
type="file"
name="docs"
ref={choosenFile}
onChange={(e) => {
setImage(e.target.files[0]);
}}
/>
</div>
<div>
<button type="submit" className="btn btn-sm btn-primary">
Send
</button>
</div>
</form>
</div>
</div>
</div>
);
};
Home.getLayout = function getLayout(Home) {
return <Theme>{Home}</Theme>;
};
export default Home;
The API route code:
import formidable from "formidable";
import fs from "fs";
export const config = {
api: {
bodyParser: false,
},
};
const post = async (req, res) => {
const form = new formidable.IncomingForm();
form.parse(req, async function (err, fields, files) {
await saveFile(files.file);
return res.status(201).json({ message: "Upload was succesfull!" });
});
};
const saveFile = async (file) => {
const data = fs.readFileSync(file.filepath);
try {
fs.writeFileSync(`./public/uploads/${file.originalFilename}`, data);
} catch (err) {
console.log('err', err);
}
await fs.unlinkSync(file.filepath);
return;
};
export default (req, res) => {
req.method === "POST"
? post(req, res)
: req.method === "PUT"
? console.log("PUT")
: req.method === "DELETE"
? console.log("DELETE")
: req.method === "GET"
? console.log("GET")
: res.status(404).send("");
};
I use the formidable package to handle formData and fs to manage file
To do this you can use axios. for more information visit npm.com/package/axios
in home.js file handle replace fetch request whit this code:
axios.post("/api/upload", data, {
onUploadProgress: (progressEvent) => {
// console.log('progressEvent', progressEvent)
if (progressEvent.bytes) {
console.log(Math.round((progressEvent.loaded / progressEvent.total)*100));
}
},
});
I am running into an issue where regardless of what component is clicked in a list of Job items, it returns the id of the last element only.
I have a key passed to the mapped list:
let activeListings = jobs.filter((job) => !job.isArchived);
activeListings?.map((job) => {
return (
<div key={job._id} className="bg-white w-8/12 py-4 my-4">
<Job
job={job}
setJob={setJobs}
handleShowDetailsToggle={handleShowDetailsToggle}
archiveToggler={archiveToggler}
setShowingResumeModal={setShowingResumeModal}
setShowingCoverLetterModal={setShowingCoverLetterModal}
showingResumeModal={showingResumeModal}
showingCoverLetterModal={showingCoverLetterModal}
getJobs={getJobs}
key={job._id}
/>
</div>
);
})
In the Job component, there is a button that when clicked opens a modal to select a file to upload and a preview.
Regardless of which Job component the Upload component is called from, it always gets passed the job._id from the final Job component listed.
Here is the resume modal component that opens on the button click:
import React, { useState } from "react";
import Upload from "../../Upload";
const AddNewResumeModal = (props) => {
const { setShowingResumeModal, job, getJobs, id } = props;
const [previewSource, setPreviewSource] = useState("");
return (
<div className="resume-modal-background">
<div className="resume-modal-container">
<button
className="close-modal-btn"
onClick={() => setShowingResumeModal(false)}
>
×
</button>
<h1 className="resume-modal-title">Upload Resume</h1>
<button onClick={() => console.log(job._id)}>Test2</button>
<Upload
resume={true}
setShowingResumeModal={setShowingResumeModal}
job={job}
getJobs={getJobs}
previewSource={previewSource}
setPreviewSource={setPreviewSource}
/>
<div></div>
</div>
</div>
);
};
export default AddNewResumeModal;
and the Upload component it renders:
import React, { useState } from "react";
import { Viewer } from "#react-pdf-viewer/core";
import "#react-pdf-viewer/core/lib/styles/index.css";
const URL = "http://localhost:8000";
const Upload = (props) => {
const {
setShowingResumeModal,
job,
getJobs,
previewSource,
setPreviewSource,
} = props;
const [fileInputState, setFileInputState] = useState("");
// const [previewSource, setPreviewSource] = useState("");
const handleFileInputChange = (e) => {
const file = e.target.files[0];
console.log(file);
previewFile(file);
};
const previewFile = (file) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = () => {
setPreviewSource(reader.result);
};
};
const handleSubmitFile = (e) => {
e.preventDefault();
if (!previewSource) return;
uploadFile(previewSource, job._id);
getJobs();
setShowingResumeModal(false);
};
const uploadFile = async (base64encodedFile, id) => {
console.log(base64encodedFile);
console.log(id);
try {
await fetch(`${URL}/upload/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ data: base64encodedFile }),
});
} catch (error) {
console.error(error);
}
};
return (
<div>
<form>
<input
type="file"
name="pdf"
id="pdf"
accept=".pdf"
onChange={handleFileInputChange}
value={fileInputState}
className="form-input"
onClick={() => console.log(job._id)}
/>
</form>
<div className="preview-container">
{previewSource ? (
<div className="viewer-container">
<Viewer fileUrl={previewSource} />
</div>
) : (
<div className="no-preview-source">Preview area</div>
)}
</div>
<button
onClick={handleSubmitFile}
type="submit"
className="upload-submit-btn"
>
Upload Resume
</button>
</div>
);
};
export default Upload;
Please help me understand how to correctly pair each job listing so that the correct id of the job is passed to the backend.
I wanted to upload images and display the image which was chosen, How to display the image after choosing. this is my code, help me display the image, I made the function to post the image, I can post multiple images in one click but i can't display the image to preview before upload , i try to use file reader but cannot display and upload.
const [pImg, setPImg] = useState([]);
const [images, setImages] = useState([]);
const addImg = (ImagesPostDto) => {
const data2 = new FormData();
[...ImagesPostDto].forEach((Images) => {
data2.append("ImagesPostDto", Images);
});
Axios.post(`/shop/${shopID}/Product/${pID}/Images`, data2)
.then((res) => {
if (res.status === 200) {
setMessage({
data: `${res.data.MESSAGE}`,
type: "alert-success",
});
onShowAlert();
}
})
.catch((err) => {
setMessage({
data: `${err.response.data.MESSAGE}`,
type: "alert-danger",
});
setLoading(false);
onShowAlert();
});
};
const handleImageChange = (e) => {
e.preventDefault();
const ProductImg = e.target.files;
setPImg(ProductImg);
const reader = new FileReader();
reader.onloadend = () => {
setPImg(ProductImg);
setImages(reader.result);
};
reader.readAsDataURL(ProductImg);
};
const handleProductSubmit = (event) => {
event.preventDefault();
addImg(pImg);
};
return (
<div>
<Form>
<p>
<Label htmlFor="file">Upload images</Label>
<input
type="file"
id="file"
onChange={handleImageChange}
accept="image/png, image/jpg, image/jpeg"
multiple
/>
</p>
</Form>
<div className="">
{/* {images.length > 0 ? (
<div>
{images.map((image) => (
<p>
<img src={images} alt="" />
</p>
))}
</div>
) : null} */}
</div>
If you want to render images then, create ObjectURL from files array and set the images State then it should work fine. I have commented the code related to API call so that we can focus on rendering the selected images.You can just simply copy this code and paste it in CodeSandBox it should work fine Here is your code a bit modified:
import "./styles.css";
import { useState } from "react";
export default function App() {
const [pImg, setPImg] = useState([]);
const [images, setImages] = useState([]);
// const addImg = (ImagesPostDto) => {
// const data2 = new FormData();
// [...ImagesPostDto].forEach((Images) => {
// data2.append("ImagesPostDto", Images);
// });
// Axios.post(`/shop/${shopID}/Product/${pID}/Images`, data2)
// .then((res) => {
// if (res.status === 200) {
// setMessage({
// data: `${res.data.MESSAGE}`,
// type: "alert-success"
// });
// onShowAlert();
// }
// })
// .catch((err) => {
// setMessage({
// data: `${err.response.data.MESSAGE}`,
// type: "alert-danger"
// });
// setLoading(false);
// onShowAlert();
// });
// };
const handleImageChange = (e) => {
e.preventDefault();
console.log("event", e);
const ProductImg = [...e.target.files];
const images = ProductImg.map((image) => URL.createObjectURL(image));
console.log("images", images);
setImages(images);
};
// const handleProductSubmit = (event) => {
// event.preventDefault();
// addImg(pImg);
// };
return (
<div>
<form>
<p>
<label htmlFor="file">Upload images</label>
<input
type="file"
id="file"
onChange={handleImageChange}
accept="image/png, image/jpg, image/jpeg"
multiple
/>
</p>
</form>
<div className="">
{images.length > 0 && (
<div>
{images.map((image, index) => (
<p key={index}>
<img src={image} alt="" />
</p>
))}
</div>
)}
</div>
</div>
);
}
You need to fetch the Images from GET API and set the response in setImages than it will show right now the images variable is empty array.
As far I can understand your requirement, you need to preview the Images Either when you have selected or After uploaded.
What you can do is, whenever you are preparing the FormData or at the time of change event, you can store each selected file's ObjectURL in another state and Easily can display these images via the State.
I am using amplify to upload and download files from my S3 bucket. There are two issues i am facing
The download link tries to download a random named json blob instead of a word document that i have in the bucket.(myword.docx comes out as random_characters.json). How can i get the actual S3 object as the filename to download.
When i execute the code, there are two download links for each file in the s3 bucket. I am unable to figure out what is wrong in the code to figure out the number of download links that are generated.
Your help is really appreciated.
import Amplify from "aws-amplify";
import "./App.css";
import { withAuthenticator } from "#aws-amplify/ui-react";
import "#aws-amplify/ui-react/styles.css";
import { Storage } from "aws-amplify";
import awsExports from "./aws-exports";
import { useEffect, useState } from "react";
Amplify.configure(awsExports);
function App({ signOut, user, sub}) {
const [fileData, setFileData] = useState();
const [fileStatus, setFileStatus] = useState(false);
const [s3DownloadLinks, setS3DownloadLinks] = useState([]);
const uploadFile = async () => {
const result = await Storage.put(fileData.name, fileData, {
level: "private",
contentType: fileData.type,
identityId: sub
});
setFileStatus(true);
console.log(21, result);
};
async function listObjectsFromS3() {
const s3Objects = await Storage.list('', {
level: "private",
//contentType: fileData.type,
identityId: sub
});
s3Objects.map(async (item) => {
console.log(30, item);
let downloadLink = await generateDownloadLinks(item.key);
console.log(30, downloadLink);
setS3DownloadLinks((s3DownloadLinks) => [
...s3DownloadLinks,
downloadLink,
]);
console.log(31, s3DownloadLinks);
});
}
async function generateDownloadLinks(fileKey) {
const result = await Storage.get(fileKey, {
level: 'private',
identityId: sub,
download: true
});
console.log(32, result);
return downloadBlob(result.Body, "filename");
}
async function downloadBlob(blob, filename) {
const a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = "output.docx";
return a;
}
useEffect(() => {
listObjectsFromS3();
}, []);
return (
<div className="App">
<h1>Hello {user.username}</h1>
<div>
<input type="file" onChange={(e) => setFileData(e.target.files[0])} />
</div>
<div>
<button onClick={uploadFile}>Upload file</button>
</div>
{fileStatus ? "File uploaded successfully" : ""}
<div id="demo" >
<h2> Your Transcribed outputs are available here</h2>
</div>
{/* List all s3 objects and download by clicking on the link */}
{s3DownloadLinks.map((item, index) => (
<div key={index}>
<a href={item} target="_blank" download="">
Link {index}
</a>
</div>
))}
<div><button onClick={signOut}>Sign out</button></div>
</div>
);
}
export default withAuthenticator(App);
I'm trying to make a file uploader in ReactJS. I managed to get it all done, except for the part that I show the image to the user. I'm able to make the name show up, but the image does not appear.
I think it's going to be easier if I show the code, so, here it goes
FileUploader Component
import React, { useState } from 'react';
import axios from 'axios'
function FileUploader() {
const [file, setFile] = useState('')
const [fileName, setFileName] = useState('Choose File')
const [selectedFile, setSelectedFile] = useState({
filePath: '',
fileName: ''
})
const handleChange = e => {
setFile(e.target.files[0])
setFileName(e.target.files[0].name)
}
const handleUpload = async e => {
e.preventDefault()
const data = new FormData()
data.append('file', file)
const res = await axios.post('http://localhost:8000/upload', data)
const { path, originalname } = res.data
setSelectedFile({filePath: path, fileName: originalname})
}
return (
<>
<div className="custom-file mb-4">
<input type="file" className="custom-file-input" id="customFile" onChange={handleChange} />
<label className="custom-file-label" htmlFor="customFile">{fileName}</label>
</div>
<button onClick={handleUpload} className='btn btn-primary btn-block mt-4'>Upload</button>
{selectedFile.filePath !== '' ? (
<div className='row mt-5'>
<div className='col-md-6 m-auto'>
<h3 className='text-center'>{selectedFile.fileName}</h3>
<img style={{ width: '100%' }} src={selectedFile.filePath} alt='' />
</div>
</div>
) : null}
</>
);
}
export default FileUploader;
I think you should use blob image by using URL.createObjectUrl
Below is updated code
import React, { useState } from 'react';
import axios from 'axios'
function FileUploader() {
const [file, setFile] = useState('')
const [fileName, setFileName] = useState('Choose File')
const [selectedFile, setSelectedFile] = useState({
filePath: '',
fileName: ''
})
const [blobImage, setBlobImage] = useState() // <= add
const handleChange = e => {
setFile(e.target.files[0])
setFileName(e.target.files[0].name)
setBlobImage(URL.createObjectURL(e.target.files[0])) // <= add
}
const handleUpload = async e => {
e.preventDefault()
const data = new FormData()
data.append('file', file)
const res = await axios.post('http://localhost:8000/upload', data)
const { path, originalname } = res.data
setSelectedFile({filePath: path, fileName: originalname})
}
return (
<>
<div className="custom-file mb-4">
<input type="file" className="custom-file-input" id="customFile" onChange={handleChange} />
<label className="custom-file-label" htmlFor="customFile">{fileName}</label>
</div>
<button onClick={handleUpload} className='btn btn-primary btn-block mt-4'>Upload</button>
{selectedFile.filePath !== '' ? (
<div className='row mt-5'>
<div className='col-md-6 m-auto'>
<h3 className='text-center'>{selectedFile.fileName}</h3>
<img style={{ width: '100%' }} src={blobImage} alt='' /> // <= change src to blobImage
</div>
</div>
) : null}
</>
);
}
export default FileUploader;
I wrote an article about file uploading with React and DnD but it's not that far off from what you're trying to accomplish:
Build A React Drag & Drop Progress File Uploader
My guess is that you're wanting to display the file preview of the image that is about to be uploaded. You can do this by loading the image into the local state, although you'll have to be careful if it's a large image as it can crash the browser.
Click the "Run code snippet" to see it in action.
// main.js
const { useState } = React;
const App = () => {
// State / Props
const [preview, setPreview] = useState(null);
// Functions
const onInputFileChange = event => {
// reset each time
setPreview(null);
// Define supported mime types
const supportedFilesTypes = ['image/jpeg', 'image/png'];
if (event.target.files.length > 0) {
// Get the type of the first indexed file
const { type } = event.target.files[0];
if (supportedFilesTypes.indexOf(type) > -1) {
const reader = new FileReader();
reader.onload = e => { setPreview(e.target.result); };
reader.readAsDataURL(event.target.files[0]);
}
}
};
return (<div><h1>Choose an image</h1><input onChange={onInputFileChange} type="file" name="file" />{preview && <img src={preview} />}</div>);
};
ReactDOM.render(<App />, document.getElementById('root'));
<body>
<div id="root"></div>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<script type="text/babel" src="main.js"></script>
</body>