Reputation: 744
I have this form and I need to be able to post data to the server through ajax, a user can upload 1 or more photos, or they may not upload any photos at all, anyway how can I send the data taken from the `type=file input and upload it to the server in the background?
Here's the relevant part of the form:
<form action="" method="POST" enctype="multipart/form-data">
@csrf
<label for="photos">Photos:</label>
<input type="file" name="photos[]" id="photos" class="form-control" multiple>
<button class="btn btn-success mt-3" onclick="ajaxify(event)">Submit</button>
</div>
</form>
And here's the relevant part of the javascript:
function ajaxify(event) {
event.preventDefault();
let failedValidation = false;
// I removed parts of the code where I load other dataand do validation, irrelevant to the question.
let photos = [];
if(document.getElementById('photos').value !== '') {
photos = document.getElementById('photos'); // I know this is incorrect, but I don't know what to do here.
}
// Here photos.value return something like c://fake/filename
// And it doesn't return more than 1 file even, so anyway I am definitely doing this wrong.
if(! failedValidation) {
axios.post('/listing/create', {
client_name: name.value,
client_phone_number: client_phone_number.value,
category: category.value,
type: type.value,
governorate: governorate.value,
city: city.value,
space: space.value,
price: price.value,
furnished_status: furnished_status.value,
payment_type: payment_type.value,
initial_deposit: initial_deposit.value,
monthly_amount: monthly_amount.value,
notes: notes.value,
photos: photos.value, // So this should be an array of uploaded files.
})
.then((resp) => {
invalid.classList.add('d-none');
console.log(resp);
})
}
}
What do I want? Is to have the file(s) I uploaded available for Laravel on the server side of the application, when I do a normal post and do dd($request->photos);
I get an array of the uploaded files, I'm not sure if that's possible with ajax/json or not, but that's what I want in order to process the photos.
A quick note, I am using the Laravel media library package if that makes any difference.
What I did so far is researching the matter and I read that I need to use FormData(), I've never used that before and I have a couple of questions, do I need to put all of my data inside that FormData()
object and feed that to axios? Or do I just need it for the photos? I haven't tried doing any of those two things yet, any guidance will be deeply appreciated.
Upvotes: 3
Views: 317
Reputation: 1508
You are only getting one file because all the file objects are stored in an array in the files
attributes. Just append them to your photos
array.
function ajaxify(event) {
event.preventDefault();
// use files attribute to get an array of the files
var photoFiles = document.getElementById("photos").files;
// using the array of files, create an array 'photos' of FormData objects
let photos = [];
for (let photo of photoFiles) {
photos.push(new FormData(photo);
}
// turn your 'photos' array into a javascript object
let photos = arr2obj(photoFiles);
// this should fix the empty array problem you were having
// pass 'photos' to the ajax data
// ....
}
EDIT: According to this post a FormData
object is required for file upload using AJAX as one of the commenters pointed out. Your array must be an array of FormData
objects.
EDIT: Sending arrays over JSON is troublesome. Turn your array into an object. You can use a simple function like this to build an object out of the array.
function arr2obj(arr) {
var obj = {};
for (let i=0; i<arr.length; i++) {
obj['photo'+i] = arr[i];
}
return obj;
}
Upvotes: 1