Last active
November 3, 2023 17:11
-
-
Save eduardoarandah/b04ebb27c46ccf6e70e9e17c7667f9f1 to your computer and use it in GitHub Desktop.
File upload with dropzone and alpine js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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