I have an action class that runs across the entire app which handles file (images) uploads:
class UploadImageAction implements UploadImageContract
{
public function handle(Request $request, $imageProperty, $image, $imageDir)
{
if ($request->hasFile($imageProperty)) {
// Handle uploading lf_image
if (!is_null($image) && Storage::exists($image)) {
// Throw exceptions here
Storage::delete($image);
}
// Throw exceptions here
return $request->file($imageProperty)->store($imageDir);
}
}
}
And I resolve()
this class withing the Service class:
public function handleAttachments($request, $report)
{
// Handle Attachments
$uploadImageAction = resolve(UploadImageAction::class);
// Handle attachment action
if($request->hasFile('attachment')) {
$report->attachment = $uploadImageAction->handle($request, 'attachment', $report->attachment, 'reports');
}
return $report;
}
Then passing it to the controller like so:
public function store(ReportsRequest $request, ReportService $reportService)
{
try
{
$reportService->storeReport($request);
return redirect('data-entry/reports')->with('success', 'Report Added Successfully');
}
catch (ImageUploadException $exception)
{
}
Reason for not calling handleAttachment()
in the store()
is because it's already passed with the validation within storeReport()
method in Service class:
$report->fill($request->validated());
$report = $this->handleAttachments($request, $report);
$report->save();
This functionality works, but sinsce I tried adding Dropzone, that's where the issue happened.
the url of the dropzone is set like so: url: "{{ route('data-entry.reports.create') }}",
. Also tried reports.store
instead of .create
This is what I get in laravel debugbar:
and in the dev tools:
JS code:
// set the dropzone container id
const id = "#kt_dropzonejs_example_2";
const dropzone = document.querySelector(id);
// set the preview element template
var previewNode = dropzone.querySelector(".dropzone-item");
previewNode.id = "";
var previewTemplate = previewNode.parentNode.innerHTML;
previewNode.parentNode.removeChild(previewNode);
var myDropzone = new Dropzone(id, { // Make the whole body a dropzone
url: "{{ route('data-entry.reports.create') }}", // Set the url for your upload script location
parallelUploads: 20,
previewTemplate: previewTemplate,
maxFilesize: 1, // Max filesize in MB
autoQueue: false, // Make sure the files aren't queued until manually added
previewsContainer: id " .dropzone-items", // Define the container to display the previews
clickable: id " .dropzone-select" // Define the element that should be used as click trigger to select files.
});
myDropzone.on("addedfile", function (file) {
// Hookup the start button
file.previewElement.querySelector(id " .dropzone-start").onclick = function () { myDropzone.enqueueFile(file); };
const dropzoneItems = dropzone.querySelectorAll('.dropzone-item');
dropzoneItems.forEach(dropzoneItem => {
dropzoneItem.style.display = '';
});
dropzone.querySelector('.dropzone-upload').style.display = "inline-block";
dropzone.querySelector('.dropzone-remove-all').style.display = "inline-block";
});
// Update the total progress bar
myDropzone.on("totaluploadprogress", function (progress) {
const progressBars = dropzone.querySelectorAll('.progress-bar');
progressBars.forEach(progressBar => {
progressBar.style.width = progress "%";
});
});
myDropzone.on("sending", function (file) {
// Show the total progress bar when upload starts
const progressBars = dropzone.querySelectorAll('.progress-bar');
progressBars.forEach(progressBar => {
progressBar.style.opacity = "1";
});
// And disable the start button
file.previewElement.querySelector(id " .dropzone-start").setAttribute("disabled", "disabled");
});
// Hide the total progress bar when nothing's uploading anymore
myDropzone.on("complete", function (progress) {
const progressBars = dropzone.querySelectorAll('.dz-complete');
setTimeout(function () {
progressBars.forEach(progressBar => {
progressBar.querySelector('.progress-bar').style.opacity = "0";
progressBar.querySelector('.progress').style.opacity = "0";
progressBar.querySelector('.dropzone-start').style.opacity = "0";
});
}, 300);
});
// Setup the buttons for all transfers
dropzone.querySelector(".dropzone-upload").addEventListener('click', function () {
myDropzone.enqueueFiles(myDropzone.getFilesWithStatus(Dropzone.ADDED));
});
// Setup the button for remove all files
dropzone.querySelector(".dropzone-remove-all").addEventListener('click', function () {
dropzone.querySelector('.dropzone-upload').style.display = "none";
dropzone.querySelector('.dropzone-remove-all').style.display = "none";
myDropzone.removeAllFiles(true);
});
// On all files completed upload
myDropzone.on("queuecomplete", function (progress) {
const uploadIcons = dropzone.querySelectorAll('.dropzone-upload');
uploadIcons.forEach(uploadIcon => {
uploadIcon.style.display = "none";
});
});
// On all files removed
myDropzone.on("removedfile", function (file) {
if (myDropzone.files.length < 1) {
dropzone.querySelector('.dropzone-upload').style.display = "none";
dropzone.querySelector('.dropzone-remove-all').style.display = "none";
}
});
CodePudding user response:
As set in your route file (in the comment) the post route is named 'data-entry.reports.store'
So change the route:
var myDropzone = new Dropzone(id, { // Make the whole body a dropzone
url: "{{ route('data-entry.reports.store') }}", // Set the url for your upload script location
parallelUploads: 20,
previewTemplate: previewTemplate,
maxFilesize: 1, // Max filesize in MB
autoQueue: false, // Make sure the files aren't queued until manually added
previewsContainer: id " .dropzone-items", // Define the container to display the previews
clickable: id " .dropzone-select" // Define the element that should be used as click trigger to select files.
});
make sure to clear your route cache using php artisan route:clear
CodePudding user response:
I figured out the issue
Since the image upload field is required, as well as the rest of the form, Dropzone doesn't read the uploaded file since there are some required fields haven't been filled!
Dropzone actually have a documentation about this: https://docs.dropzone.dev/configuration/tutorials/combine-form-data-with-files
Since the files are combined with data in the Service class, I need to set autoProcessQueue
to false
and trigger it with the submit button like myDropzone.processQueue();
once all of the fields are filled to send everything to DB at once.