I have a problem with saving pictures in the database. I want to do a post Method, where i can safe a file in a directory and save the picture link in the database.
Here is my Code:
`const toBase64 = file => new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => resolve(reader.result)
reader.onerror = error => reject(error)
})`
` const [base64Image, setBase64Image] = useState("")
const [imagePath, setImagePath] = useState("")
const fileInput = useRef(null)`
`const onFileInputChange = async (e) => {
const file = fileInput.current.files[0]
if (!file) return
const base64 = await toBase64(file)
setBase64Image(base64)}`
` const handleSubmitImage = async (e) => {
e.preventDefault()
if (!base64Image) return
const response = await fetch("/public", {
method: "POST",
headers: {
"content-type": "application/json"
},
body: JSON.stringify(base64Image)
})
const data = await response.json()
setImagePath(data.filePath)
}`
Post:
`const handleSubmit = async (e) => {
e.preventDefault()
setIsLoading(true)
setErrors(defaultModel)
const result = validateModel(post)
if (!result.isValid) {
setErrors(result.errors)
setIsLoading(false)
return
}
if (post.id) {
await updatePost(post, session.accessToken)
alert("Post updated!")
router.push(`/posts/${post.id}`)
} else {
const newPost = await createPost(post, session.accessToken)
alert("Post created!")
router.push(`/posts/${newPost.id}`)
}
setIsLoading(false)
}
`
` <fieldset onSubmit={handleSubmitImage} className={styles.form}>
<p>Image:</p>
<input value={post.image}
type="file"
accept=".png,.jpg"
ref={fileInput}
onChange={onFileInputChange}
/>
{/* eslint-disable-next-line #next/next/no-img-element */}
{base64Image && <img src={base64Image} style={{width: "1000px", height: "1000px"}} alt={""}/>}
{imagePath && <p>
<Link href={`http://localhost:3000${imagePath}`}
passHref><a>http://localhost:3000{imagePath}</a></Link>
</p>
}
</fieldset>`
Right now i can connect to the Explorer and pick an Image. I can also display the image. If i press on create, it doesnt work properly with saving the image in the database.
Related
I am trying to display an image on a profile of a user. I have been able to fetch the blob from the API and convert it to a URL blob but when I am trying to return it from the function and into the SRC of the tag, nothing is being displayed.
Previously I was simply displaying the image with <src = ""> and the src that I have put in the function, but when I implemented authentication, this no longer worked because there was a 401 unauthenticated error since no bearer token was sent with the request.
Output:
//profile.js
export const Profile = () => {
const [userProfileInformation, setUserProfileInformation] = useState([]);
const [isLoading, setLoading] = useState(true);
const { userId } = useParams();
useEffect(() => {
getUserProfileInformation().then(() => {
setLoading(false);
});
}, []);
const getUserProfileInformation = async () => {
const response = await UserService.getUserProfileInformation(userId)
.then(response => response.json())
.then(data => {
setUserProfileInformation(data);
});
}
const getProfileImage = async () => {
const src = config.URL + "/users/" + userProfileInformation.userId + "/image/download";
const options = {
headers: {
"Authorization" : `Bearer
${AuthService.getCurrentlyAuthenticatedUser().accessToken}`,
}
};
fetch(src, options)
.then(res => res.blob())
.then(blob => {
console.log(blob);
let url = URL.createObjectURL(blob);
console.log(url);
return url;
});
}
if (isLoading) {
return (
<div id="loading">
<h2>Loading...</h2>
</div>
)
}
return (
<div>
<AppNavbar />
<div className="profileCard">
<img id="profileImg" src={getProfileImage()}/>
<h1>{getFullName(userProfileInformation.firstName, userProfileInformation.lastName)}</h1>
<h2 id="email" role="email">{userProfileInformation.email}</h2>
<h2>{userProfileInformation.location}</h2>
)
}
Any help would be appreciated, thanks.
I am trying to stream a mp4 file that is on my computer. I am able to upload and delete the files. When the upload completes and click the link. it routes me to the page and I only see {}. and I get the following errors:
GET http://localhost:8000/read/c94e2bfe215bb8821c5c8dc22c8dc1b4.mp4 400 (Bad Request)
favicon.ico:1 GET http://localhost:8000/favicon.ico 404 (Not Found)
I even uploaded a picture to see to check if the mp4 file was too big, but the picture did not load as well.
Here is my code for my server:
// route for streaming a file
app.get('/read/:filename',async(req,res)=>{
const{filename}= req.params
try{
const readstream = await gfs.createReadStream({filename})
res.header("Content-Type","video/mp4");
res.header("X-Content-Type-Options", "nosniff");
res.header("Accept-Ranges", "bytes");
res.header("Content-Length",903746);
readstream.pipe(res)
}catch(err){
res.status(400).send(err)
}
})
Here is the code for react
function App() {
const [file, setFile] = React.useState(null);
const [files, setFiles] = React.useState([]);
const filehandler = (e) => {
if (e.target.files != null || e.target.files[0] != null) {
setFile(e.target.files[0]);
}
};
const uploadFile = async (e) => {
e.preventDefault();
if (file) {
const fd = new FormData();
fd.append("file", file);
const res = await axios.post("http://localhost:8000/upload", fd);
setFiles(files.concat(res.data))
}
};
const fetchFiles = React.useCallback(async () => {
const res = await axios.get("http://localhost:8000/files");
setFiles(res.data);
}, []);
const removeFile = React.useCallback(
async (filename, index) => {
const res = await axios.delete(
`http://localhost:8000/delete/${filename}`
);
if (res.status === 200) {
let temp = [...files];
console.log(temp);
temp.splice(index, 1);
setFiles(temp);
}
},
[files]
);
React.useEffect(() => {
fetchFiles();
}, [fetchFiles]);
return (
<div className="App">
<form className="Form" onSubmit={uploadFile}>
<input type="file" onChange={filehandler} />
<button type="submit">upload</button>
</form>
<div className="Media">
{files.map((file, i) => (
<div key={file._id} className="Item">
<a
className="Link"
href={`http://localhost:8000/read/${file.filename}`}
>
{file.filename}
</a>
<button
type="button"
onClick={() => {
removeFile(file.filename, i);
}}
>
remove
</button>
</div>
))}
</div>
</div>
);}
Your router is sending 400 after catching an exception. Print exception message using console.log(err) in your catch block to determine what exactly goes wrong it try block's code
I'm using Vue with Laravel and I tried to do a simple crud which is working good regarding things like title or description of an article (text-fields) but when I try to send an image file, it doesn't work. I have tried formData but to no avail.
This is my form in template, title goes in the database with no problem, if I console log selectedFile then it shows the file selected correctly but the addArticle method not attaching the images
<form #submit.prevent="addArticle" class="container">
<label>Title</label>
<input type="text" v-model="article.title" />
<label>Image</label>
<input type="file" v-on:change="selectedFile" />
<button type="submit">Create</button>
</form>
This is my script
<script>
export default {
data() {
return {
fileSelected: null,
article: {},
};
},
methods: {
addArticle() {
var formData =new FormData();
formData.append(this.article.image, this.fileSelected);
axios
.post("http://localhost:8000/api/articles", this.article)
.then((response) => this.$router.push({ name: "ArticlesList" }))
.catch((err) => console.log(err))
.finally(() => (this.loading = false));
}
,
selectedFile(event) {
this.fileSelected = event.target.files[0];
},
},
};
</script>
this is my code
<input type="file" #change="onFileChange">
onFileChange(e) {
this.sendphoto = e.target.files[0];
},
editUser() {
var self = this;
let formData = new FormData();
formData.append("image" , self.sendphoto )
let config = {
header : {
'Content-Type' : 'multipart/form-data'
}
}
axios.post('/edit-user' , formData , config)
.then(function (response) {
})
.catch(function (error) {
console.log(error);
})
},
You are creating a FormData object but you are not sending it within your Axios request.
In order to send the file and form data, you have to append everything to FormData object.
<script>
export default {
data() {
return {
fileSelected: null,
article: {},
};
},
methods: {
addArticle() {
var formData =new FormData();
formData.append('image', this.fileSelected);
formData.append('title', this.article.title);
axios
.post("http://localhost:8000/api/articles", formData)
.then((response) => this.$router.push({ name: "ArticlesList" }))
.catch((err) => console.log(err))
.finally(() => (this.loading = false));
}
,
selectedFile(event) {
this.fileSelected = event.target.files[0];
},
},
};
</script>
this worked in sending image files as string on database, hopefully it helps other people that are having similar problems
setup() {
const base64 = ref()
const changeFile= async(event) => {
const file = event.target.files[0];
base64.value = await convertBase64(file);
}
const convertBase64 = (file) => {
return new Promise ((resolve, reject) => {
const fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onload = () => {
resolve(fileReader.result)
}
fileReader.onerror = (error) => {
reject(error)
}
})
}
const form = reactive({
title: " ",
body: " ",
image: base64,
})
const submitForm = () => {
axios.post("http://localhost:8000/api/articles", form)
}
return { changeFile, submitForm, form}
},
I tried to rewrite this Submit function to use react query useMutation but i get errors.Does somebody know how to change this to be writen with useMutation.I thank you very much for every hint and every answer to this question.
async function handleSubmit(e) {
e.preventDefault();
try {
if (file) {
// if file is set send it to cloudinary api
const url = `https://api.cloudinary.com/v1_1/${CLOUD_NAME}/upload`;
loading(true);
const formData = new FormData();
formData.append("file", file);
formData.append("upload_preset", UPLOAD_PRESET);
const res = await fetch(url, {
method: "POST",
body: formData,
});
// get data and pull out 1000w image url
const data = await res.json();
const fileUrl = await data.eager[0].secure_url;
console.log(fileUrl);
setError("");
if (album.trim() !== "" && color.trim() !== "" && fileUrl) {
// Craeting Date form
const albumData = new FormData();
albumData.append("name", album);
albumData.append("bckImgUrl", fileUrl);
albumData.append("color", color);
// change albumData to json
const object = {};
albumData.forEach((value, key) => (object[key] = value));
// sending data to /api/v1/albums
const res = await fetch(`${SERVER_API}/api/v1/albums`, {
method: "POST",
body: JSON.stringify(object),
headers: {
"Content-Type": "application/json",
},
});
if (!res.ok) {
const message = `An error has occured: ${res.status}`;
setError(message);
}
const data = await res.json();
const id = await data.data._id;
loading(false);
history.push(`/albums/${id}`);
} else {
setError("Please enter all the field values.");
}
} else {
setError("Please select a file to add.");
}
} catch (error) {
error.response && setError(error.response.data);
}
}
Something like that. As simple as possible
Codesandbox link for demo
import { Fragment, useState } from "react";
import axios from "axios";
import { useMutation } from "react-query";
const senRequest = async () => {
return await axios.get("https://jsonplaceholder.typicode.com/posts");
};
export default function App() {
const [val, setVal] = useState("");
const [result, setResult] = useState([]);
const { mutate } = useMutation(senRequest); // if you need to send data configure it from here
const handleSubmit = (e) => {
e.preventDefault();
mutate(senRequest, { // And send it in here.
onSuccess: ({ data }) => {
setResult(data.slice(0, 5));
}
});
};
return (
<div className="App">
<form onSubmit={handleSubmit}>
<input value={val} onChange={(e) => setVal(e.target.value)} />
<button type="submit">Submit</button>
</form>
{result.map((el) => (
<Fragment key={el.id}>
<div
style={{
width: "100%",
borderBottom: "1px solid gray"
}}
>
<span>{el.title}</span>
<span>{el.body}</span>
</div>
</Fragment>
))}
</div>
);
}
little refactor suggestion :)
import React from "react";
import { useHistory } from "react-router-dom";
import { UPLOAD_PRESET, CLOUD_NAME, SERVER_API } from "../../config";
// to don't redefine this function on each rerender they can be defined out of component
const uploadImage = async file => {
const url = `https://api.cloudinary.com/v1_1/${CLOUD_NAME}/upload`;
const formData = new FormData();
formData.append("file", file);
formData.append("upload_preset", UPLOAD_PRESET);
const res = await fetch(url, {
method: "POST",
body: formData,
});
if (!res.ok) {
throw new Error(`Can't upload image. ${res.status}`)
}
const data = await res.json();
return await data.eager[0].secure_url;
}
const createAlbum = async data => {
const res = await fetch(`${SERVER_API}/api/v1/albums`, {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
},
});
if (!res.ok) {
throw new Error(`An error has occurred: ${res.status}`)
}
const json = await res.json();
return json.data._id;
}
const Form = ({ file, loading: setLoading, setError, album, color, children }) => {
let history = useHistory();
const clearError = () => setError("")
const handleSubmit = async e => {
e.preventDefault();
clearError();
try {
if (!file) {
throw new Error("Please select a file to add.");
}
if (!album.trim() || !color.trim()){
throw new Error("Please enter all the field values.");
}
setLoading(true);
const fileUrl = await uploadImage(file);
const data = {
"name": album,
"bckImgUrl": fileUrl,
"color": color
};
const albumId = await createAlbum(data);
history.push(`/albums/${albumId}`);
} catch (error) {
setError(error.message);
} finally {
setLoading(false)
}
}
return <form onSubmit={handleSubmit}>{children}</form>
}
export default Form
When I request api, I want to make conditional according to the answer, but it doesn't assign the value I want to errorMessageUploaded. Do you have an idea?
I want to get a message when the error comes from api, but when the response comes errormessageupload variable without ending the request.
Not working conditional.
let uploadLoading = false;
let errorMessageUploaded = null;
`function Previews(props) {
const [files, setFiles] = useState([]);
const [test, testFile] = useState(null);
const { getRootProps, getInputProps } = useDropzone({
noClick: props.uploadDisable,
accept: "application/vnd.ms-excel,
application/vnd.openxmlformats-
officedocument.spreadsheetml.sheet",
onDrop: acceptedFiles => {
uploadLoading = true;
var file = acceptedFiles[0];
fileName = file.path;
const reader = new FileReader();
let data = {
file: null,
purchase_order_id: props.purchaseorderid
};
reader.onload = event => {
uploadLoading = true;
data.file = event.target.result.replace(
"data:application/vnd.openxmlformats-
officedocument.spreadsheetml.sheet;base64,",
""
);
});
(async () =>
await axios
.post(
baseUrl + "v1/purchaseorder/uploadpurchaseorder",
data,
axiosConfig
)
.then(response => {
uploadLoading = false;
errorMessageUploaded = null;
window.location.reload();
})
.catch(error => {
errorMessageUploaded = "test";
uploadLoading = false;
throw error;
}))();
reader.readAsDataURL(file);
}
});
const thumbs = files.map(file => (
<FontAwesomeIcon icon={faFileExcel}
className="excelUploadThumbs" />
));
useEffect(
() => () => {
// Make sure to revoke the data uris to avoid memory leaks
files.forEach(file => URL.revokeObjectURL(file.preview));
},
[files]
);
return uploadLoading == false ? (
<section className="container">
<div {...getRootProps({ className: "dropzone" })}>
<input {...getInputProps()} />
<p className="dropzoneText1">Drop your file here</p>
<p className="dropzoneText2">or</p>
<p className="dropzoneText3">Select file</p>
</div>
<aside style={thumbsContainer}>{thumbs}</aside>
</section>
) : errorMessageUploaded != null ? (
<section className="container">
<div className="displayErrorDiv">
<p className="serviceError"> {errorMessageUploaded} </p>
</div>
</section>
) : (
<section className="container">
Data is uploading...
<aside style={thumbsContainer}>{thumbs}</aside>
</section>
);
}`
Code unclear but these may be helpful.
use uploadLoading & errorMessageUploaded with useState
need cancelToken
let source = Axios.CancelToken.source();
const Send = async (url, method, data) => {
try {
source && source.cancel("Operation canceled due to new request.");
source = Axios.CancelToken.source();
return await Axios({ method, url, data, cancelToken: source.token });
} catch (error) {
if (Axios.isCancel(error)) {
return Promise.resolve("canceled");
} else {
return Promise.reject(error);
}
}
};