Skip to content

Instantly share code, notes, and snippets.

@eduardoarandah
Last active November 3, 2023 17:11
Show Gist options
  • Save eduardoarandah/b04ebb27c46ccf6e70e9e17c7667f9f1 to your computer and use it in GitHub Desktop.
Save eduardoarandah/b04ebb27c46ccf6e70e9e17c7667f9f1 to your computer and use it in GitHub Desktop.
File upload with dropzone and alpine js
SCREENSHOT: https://prnt.sc/127reb8
REQUIRES:
- 3 api endpoints: store, destroy, list
- a csrf_token for security
INCLUDES: a laravel controller, but can be used anywhere
{{-- dropzone --}}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.2/min/dropzone.min.js" integrity="sha512-VQQXLthlZQO00P+uEu4mJ4G4OAgqTtKG1hri56kQY1DtdLeIqhKUp9W/lllDDu3uN3SnUNawpW7lBda8+dSi7w==" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.2/dropzone.min.css" integrity="sha512-jU/7UFiaW5UBGODEopEqnbIAHOI8fO6T99m7Tsmqs2gkdujByJfkCbbfPSN4Wlqlb9TGnsuC0YgUgWkRBK7B9A==" crossorigin="anonymous" />
{{-- alpine --}}
<script src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine.min.js" defer></script>
<script charset="utf-8">
Dropzone.autoDiscover = false;
function alpine() {
return {
files: [],
init() {
this.dropzone();
this.fetch();
document.addEventListener('upload', () => this.fetch());
},
fetch() {
fetch('{{ $list }}').then(r => r.json()).then(r => this.files = r);
},
deletefile(file) {
fetch('{{ $destroy }}', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify({
file: file
})
})
.then(r => r.json())
.then(r => console.log(r))
.then(this.fetch());
},
dropzone() {
new Dropzone("#dropzone", {
'headers': {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
init() {
this.on("complete", () => {
document.dispatchEvent(new CustomEvent('upload'));
});
},
url: '{{ $store }}'
});
}
}
}
</script>
<form action="{{ $store }}" class="dropzone" id="dropzone"></form>
<h2 class="mt-3">Files: </h2>
<table x-data="alpine()" class="table mt-3" x-init="init">
<thead>
<tr>
<th>File</th>
<th></th>
</tr>
</thead>
<tbody>
<template x-for="file in files" :key="file">
<tr>
<td>
<span x-text="file"></span>
</td>
<td>
<div class="d-lg-flex align-items-center justify-content-end">
<a class="btn btn-sm btn-default" target="_blank" x-bind:href="'/storage/'+file">
<i class="la la-eye"></i>
View</a>
<a class="ml-2 btn btn-sm btn-default" download x-bind:href="'/storage/'+file">
<i class="la la-download"></i>
Download
</a>
<button class="ml-2 btn btn-sm btn-default" x-on:click="if(confirm('Are you sure?')) deletefile(file)">
<i class="la la-trash"></i>
Delete
</button>
</div>
</td>
</tr>
</template>
</tbody>
</table>
<?php
// example:
Route::get('upload/{user}', 'UploadController@index')->name('upload.index');
Route::post('upload/{user}', 'UploadController@store')->name('upload.store');
Route::delete('upload', 'UploadController@destroy')->name('upload.destroy');
Route::get('list/{user}', 'UploadController@list')->name('upload.list');
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Storage;
class UploadController extends Controller
{
public function index(User $user)
{
return view("admin.upload.index", compact("user"));
}
public function store(User $user, Request $request)
{
$data = $request->validate([
"file" => "required|file",
]);
$file = $data["file"];
$dir = $this->getUserDirectory($user);
$filename = date("Y-m-d-hms") . "/" . $file->getClientOriginalName();
$disk = "public";
$path = $file->storeAs($dir, $filename, $disk);
try {
return response()->json([
"success" => "File saved to $path",
]);
} catch (Exception $exception) {
return response()->json([
"error" => "There was an error saving file: $file",
]);
}
}
public function list(User $user)
{
$dir = $this->getUserDirectory($user);
return collect(Storage::disk("public")->allFiles($dir))->sort();
}
public function destroy(Request $request)
{
$data = $request->validate([
"file" => "required|string",
]);
$file = $data["file"];
try {
// exists?
if (!Storage::disk("public")->exists($file)) {
return response()->json([
"success" => "File doesn't exist $file",
]);
}
Storage::disk("public")->delete($file);
return response()->json([
"success" => "File deleted: $file",
]);
} catch (Exception $exception) {
return response()->json([
"error" => "There was an error deleting file: $file",
]);
}
}
public function getUserDirectory(User $user): string
{
return "uploads/" . $user->id . "/";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment