Multiple file upload with laravel and vue 3 - javascript

I am trying to upload multiple files with laravel and vue 3. I have 3 attributes user_files, book_files[]
<input
type="file"
class="form-control"
name="user_files[]"
#change="onFileChange"
multiple
id="user_files"
placeholder="User details"
/>
</div>
const form = reactive({
first_name: "",",
hourly_rate: 0,
user_files: [],
book_files: []
user_name: "",
course_date: "",
});
const onFileChange = (e) => {
for (let i = 0; i < e.target.files.length; i++) {
form.user_files.push(e.target.files[i]);
}
};
const { errors, storeUser } = useUsers();
const saveUser = async () => {
await storeUser({ ...form });
};
return {
form,
saveUser,
onFileChange,
};
How can I rewrite the function onFileChange for multiple attributes, right now it is only for `user_files.
const storeUser = async (data, medical_file) => {
let formData = new FormData();
(data.user_files ?? []).forEach((file, key) => {
formData.append("user_files[]", file);
});;
errors.value = "";
try {
const status = await http.post("/api/users", formData, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
Also in above js function, I need to append rest of the data like first_name, user_name and others into the formData as well, and loop over the other files along with user_files. How should I do that (data.medical_file ?? []).forEach((file, key) => { formData.append("medical_file[]", file); });; in this function.

Related

I can't upload image files from .vue to my database

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}
},

How to return value from in FireReader Promesse

I'm learning Javascript and i need a little help, my brain is broken.
My objectif is to parse my input (text and files) to JSON and send it with fetch API (for getting it on Symfony).
I use this javascript for translate the files to base64 and finaly JSON. It's works ! But ... i don't understand how i can return my jsonDataFile from my New FileReader to my body in my fetch API.
<li><input type="file" id="file" name="file" ref="file" v-on:change="handleFileUpload()" multiple></li>
setFile_to_B64_to_JSON(){
const files = this.files
//return new Promise((jsonDataFile, jsonData) => {
let formDataFile = new FormData();
for (let i = 0; i < files.length; i++) {
const file = files[i];
formDataFile.append('files[' + i + ']', file);
const reader = new FileReader();
reader.onloadend = () => {
const base64String = reader.result
.replace("data:", "")
.replace(/^.+,/, "")
let jsonDataFile = JSON.stringify(base64String)
console.log(jsonDataFile)
}
reader.readAsDataURL(file)
return jsonDataFile
}
}
async pushProject(){
var buildjsoncontent = ''
var buildjsonfile = ''
buildjsoncontent = this.setProject();
buildjsonfile = this.setFile_to_B64_to_JSON();
let optionsFiles = {
method: 'POST',
headers: { "Content-Type": "application/json" },
body:
buildjsonfile
}
fetch('http://127.0.0.1:8000/addimg', optionsFiles)
.then(response => response.json())
.then(data1 => {
console.log(data1)
})
.catch(error => console.error(error))
}
The methods setProject() is an another methods for send my input type text to JSON and it works.
If you have any idea or little tips, thanks in advance :)

How to upload an array of images

I have these methods for choosing and uploading the image, but I am not sure about where the error is, if it is in the code or in the API
const [imagens, setImagens] = useState([])
function choseImage(event) {
imagens.push(URL.createObjectURL(event.target.files[0]))
}
const upload = () => {
const fd = new FormData();
// imagens is the array of images
fd.append('imagem', imagens)
fetch('http://localhost:5000/api/Upload', fd)
.then(res => {
console.log(res)
});
}
here is the UploadController, the messege is:
System.NullReferenceException: 'Object reference not set to an instance of an object.' file was null.
[HttpPost]
public async Task Post(IFormFile file)
{
var nomeArquivo = (file.FileName);
var uploads = Path.Combine(Directory.GetCurrentDirectory(), "wwwRoot\\Upload", nomeArquivo);
if (!Directory.Exists(uploads)) Directory.CreateDirectory(uploads);
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(uploads, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
}
}
this is my first freelance project, that is the last thing missing, Thanks in advance
Your code is nearly complete with a couple of changes commented in the code below. In your React component you can do something like the following.
export const ImageFileUpload = () => {
const [images, setImages] = useState([]);
const onFileChange = (files) => {
setImages(f => [...f, ...files]);
};
const handleClick = (e) => {
e.preventDefault();
const formData = new FormData();
for (let i = 0; i < images.length; i++) {
// 'images' name of the formData values must match the action method param on your controller
formData.append(`images`, images[i]);
}
// Make sure you api is running on the same endpoint or you need to set up CORS
fetch('https://localhost:5001/fileupload', {
body: formData,
method: "POST" // Make sure you add the method POST to your request when API is only accepting POST
}).then(res => console.log(res));
};
return (
<form>
<input type="file" multiple={true} onChange={e => onFileChange(e.target.files)} />
<button onClick={handleClick}>Upload</button>
</form>
)
};
Your controller should look like this.
[ApiController]
[Route("[controller]")]
public class FileUploadController : ControllerBase
{
[HttpPost]
// 1. The name of the parameter must match the name of the `formData`
// 2. This method should take `List<IFormFile>`
public async Task Upload(List<IFormFile> images)
{
foreach (var image in images)
{
var nomeArquivo = (image.FileName);
var uploads = Path.Combine(Directory.GetCurrentDirectory(), "wwwRoot\\Upload\\", nomeArquivo);
if (!Directory.Exists(uploads)) Directory.CreateDirectory(uploads);
using (var fileStream = new FileStream(Path.Combine(uploads, image.FileName), FileMode.Create))
{
await image.CopyToAsync(fileStream);
}
}
}
}

How to upload Multiple Data to Firebase Store without duplicate

I've googled about how to send and get the Multiple data on firebase.
but none of them worked for me. and some of them work strangely like my code.
My Code uploads multiple data. but it is uploaded in duplicate.
What I wanted to do is uploading different data separately.
Please let me know what I have to modify.
Here is My code.
const [file, setFile] = useState([]);
function handleChange(e) {
for (let i = 0; i < e.target.files.length; i++) {
const newFile = e.target.files[i];
setFile(newFile);
}
}
function uploadImageAsPromise() {
Promise.all(
[file].map((file) => {
return new Promise(() => {
const uploadTask = storage.ref(`files/${file.name}`).put(file);
uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, (snapshot) => {
console.log(snapshot);
storage
.ref("files")
.child(file.name)
.getDownloadURL()
.then((url) => {
//post image inside the db
const itemObj = {
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
caption: file.name,
fileUrl: url,
size: snapshot._delegate.bytesTransferred,
};
db.collection("myFiles").add(itemObj);
setUploading(false);
setOpen(false);
setFile(null);
});
})
}),
storage
.ref("files")
.child(file.name)
.getMetadata()
.then((meta) => {
console.log(meta.size);
})
}))
}
<input type="file" onChange={handleChange} multiple />
<button onClick={uploadImageAsPromise}>Upload</button>

How to implemet useMutation from react-query in handleSubmit

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

Categories

Resources