X-Splade-File Component
The File Component is a dedicated component you can use to select files. This component is based mainly on the Input component but provides additional logic to display the filename of the selected file. You don't have to manually use the input event to bind the selected files to the form. Splade does this for you.
<x-splade-form :default="$user"> <x-splade-file name="avatar" /></x-splade-form>
The component supports selecting multiple files as well by adding the multiple
attribute.
<x-splade-form :default="['documents' => []]"> <x-splade-file name="documents[]" multiple /></x-splade-form>
Image preview
You might want to show a preview of the selected image. You may use the form.$fileAsUrl
method to generate a base64-encoded representation of the image, and use it as the source of an img
element. In addition, with the show-filename
attribute, you can disable displaying the filename.
<x-splade-form> <x-splade-file name="avatar" :show-filename="false" /> <img v-if="form.avatar" :src="form.$fileAsUrl('avatar')" /> </x-splade-form>
FilePond
The FilePond integration comes with a default stylesheet which you should import into the main JavaScript file. If you've used the automatic installer, it has already done this for you.
import "@protonemedia/laravel-splade/dist/style.css";import { renderSpladeApp, SpladePlugin } from "@protonemedia/laravel-splade";
Now you may add the filepond
attribute to the component:
<x-splade-file name="avatar" filepond />
This works for uploading multiple files as well:
<x-splade-file name="avatars[]" multiple filepond />
You can instantiate FilePond with a custom set of options by passing a JavaScript object to the filepond
attribute. To pass a PHP array, you may use the :filepond
attribute (note the colon).
<x-splade-file name="avatar" filepond="{ allowDrop: false }" /> <x-splade-file name="avatar" :filepond="['allowDrop' => false]" />
Image Preview
FilePond can render a downscaled preview of the selected image by adding the preview
attribute to the component:
<x-splade-file name="avatar" filepond preview />
Validate type and size
FilePond supports validating the selected file based on the type and size. To validate the type, you may use the accept
attribute:
<x-splade-file name="avatar" filepond accept="image/png" />
You may use the min-size
or max-size
attribute to validate the file size. You may use both attributes at once as well:
<x-splade-file name="avatar" filepond min-size="100KB" max-size="5MB" />
Please be aware that both features are client-side validation. For security reasons, make sure you use server-side validation as well.
Validate images
FilePond supports validating the dimensions of a selected image. For example, you may use the min-width
and min-height
attributes to validate the minimum width and height. Similarly, to validate the maximum width and height, you may use the max-width
and max-height
attributes:
<x-splade-file name="avatar" filepond min-width="200" min-height="200" /> <x-splade-file name="header" filepond max-width="1500" max-height="1500" />
If you want to validate against an exact size, you may use the width
and height
attributes:
<x-splade-file name="poster" filepond width="720" height="576" />
Alternatively, you may specify a minimum or maximum resolution:
<x-splade-file name="avatar" filepond :min-resolution="300 * 300" /> <x-splade-file name="header" filepond :max-resolution="1500 * 1200" />
Adding remote files
FilePond can upload a file using a Remote URL. The form
object has an $addFile
method that allows you to pass a URL to a FilePond instance. You must pass the field as the first argument and the URL as the second argument. In the example below, we'll use a regular input element to set the Remote URL:
<x-splade-form> <x-splade-file filepond server name="avatar" /> <x-splade-input name="remote_url" label="Remote URL" /> <button @click.prevent="form.$addFile('avatar', form.remote_url)"> Add from Remote URL </button></x-splade-form>
If you need to add multiple files at once, you may use the $addFiles
method, which accepts an array as a second argument.
Asynchronous uploads
FilePond supports uploading the file to the server before the form is submitted. First, you must register a supporting route using the spladeUploads()
method on the Route
facade. As of version 0.7.6, the automatic installer does this for you. If you need to register the route manually, make sure it uses the web
Middleware, for example, in web.php
:
Route::spladeUploads();
Next, in the template, add the server
attribute to the component. From now on, when a user drops a file into the FilePond instance, it will immediately start uploading to the server.
<x-splade-file name="avatar" filepond server />
Splade will store the file in a temporary directory and report the path to the file back to the File component. So when the user submits the form, it will send this path instead of uploading the file.
There are three ways of handling the temporary upload. You may choose the option that best fits your needs. First, you may use the HandleSpladeFileUploads
class, for example, in your controller:
use Illuminate\Http\Request;use ProtoneMedia\Splade\FileUploads\HandleSpladeFileUploads; public function store(Request $request){ HandleSpladeFileUploads::forRequest($request); $request->validate([ 'photo' => ['required', 'file', 'image'], ]); $path = $request->file('photo')->store('images');}
The HandleSpladeFileUploads
class will loop through the request data and transform paths to temporary uploads back into UploadedFile
instances. Make sure you call the forRequest()
method before validating the request. Instead of looping through all request data, you may also pass the key (or an array of keys):
HandleSpladeFileUploads::forRequest($request, 'photo');
The second option is to use a Route Middleware. You may use the same HandleSpladeFileUploads
class as the example above. Using the fully qualified class name will loop through all request data, but you may also specify one or more keys using the static for
method.
Route::post('podcast', StorePodcastController::class) ->middleware(HandleSpladeFileUploads::class); Route::post('podcast', StorePodcastController::class) ->middleware(HandleSpladeFileUploads::for('photo'));
The last option is to use a Form Request. Then, you only have to implement the HasSpladeFileUploads
interface and use the file
validation rule. Splade will automatically extract the keys from the rules.
use Illuminate\Foundation\Http\FormRequest;use ProtoneMedia\Splade\FileUploads\HasSpladeFileUploads; class StorePodcastRequest extends FormRequest implements HasSpladeFileUploads { public function rules() { return [ 'photo' => 'required|file|image', ]; }}
Cleanup temporary uploads
It may happen that temporarily uploaded files are not being used and will fill the temporary directory. Splade comes with a built-in Artisan command to delete all unused files that are older than one hour:
php artisan splade:cleanup-uploads
You may change the lifetime of temporary files with the file_uploads.temporary_file_lifetime
key in the splade.php
configuration file.
Custom temporary directory
By default, Splade uses the /storage/splade-temporary-file-uploads
directory for temporary uploads. If you want to use a custom Filesystem disk, you may update the file_uploads.disk
key in the splade.php
configuration file. For now, it only supports local disks.
Customize FilePond styling
FilePond uses an SCSS stylesheet to style the library. Our stylesheet extends the vendor stylesheet (of FilePond) and adds some Tailwind-specific tweaks. Make sure your bundler handles SCSS stylesheets correctly, for example, by installing sass
. The splade:publish-form-stylesheets
Artisan command copies the stylesheet to the resources
directory of your app.
npm install sass -D php artisan splade:publish-form-stylesheets
Then import the stylesheet in your main JavaScript file (instead of the default @protonemedia/laravel-splade/dist/style.css
stylesheet):
import "../css/filepond.scss"
Working with existing files
FilePond allows you to show existing files in the UI. Splade comes with a set of tools to help you present and preserve existing files. Imagine you use the file input to replace a user's avatar while still showing the current one. You may use the ExistingFile
class to load the current avatar:
use ProtoneMedia\Splade\FileUploads\ExistingFile; $avatar = ExistingFile::fromDisk('public')->get('avatars/user.jpeg');
Then in the Blade template, you may use the ExistingFile
instance as default form data:
<x-splade-form :default="['avatar' => $avatar]"> <x-splade-file filepond preview name="avatar" /> <x-splade-submit /></x-splade-form>
If you submit the form without changing the avatar, the avatar
field will be empty, but Splade will submit an avatar_existing
field to inform you the current avatar hasn't changed. When you access that key from the Request
instance, it will give you an instance of ExistingFile
again:
public function update(Request $request){ HandleSpladeFileUploads::forRequest($request); // This is an instance of ExistingFile: $existingAvatar = $request->avatar_existing;}
Multiple existing files
You may also use multiple existing files with a file input that allows uploading multiple files. For example, instead of passing one instance of ExistingFile
, you may now use an array:
$photos = [ ExistingFile::fromDisk('public')->get('photos/1.jpeg'), ExistingFile::fromDisk('public')->get('photos/2.jpeg'),];
Luckily, the get
method also accepts an array:
$photos = ExistingFile::fromDisk('public')->get([ 'photos/1.jpeg', 'photos/2.jpeg',]);
Just like using a single existing file as default form data, you may do the same for multiple files:
<x-splade-form :default="['photos' => $photos]"> <x-splade-file filepond multiple preview name="photos[]" /> <x-splade-submit /></x-splade-form>
The user may submit the form with existing and new files when dealing with multiple files. In addition, FilePond allows the user to reorder the files as well. So how would you handle such forms in the controller? Like the avatar example, Splade will submit a photos
array with new files and a photos_existing
array with the existing files. Additionally, the request data will have a photos_order
key representing the order, as a user can mix existing and new files.
You can combine existing and new files with their order manually. However, Splade comes with a orderedSpladeFileUploads()
method that you may call on a Request
instance. This method returns a Collection
with SpladeFile
instances. The files are already in the correct order, and have helper methods like exists()
and doesntExist()
to determine the file's nature.
use ProtoneMedia\Splade\FileUploads\SpladeFile; public function update(Request $request){ $request->orderedSpladeFileUploads('photos')->each(function (SpladeFile $file) { if ($file->exists()) { // This is an instance of ExistingFile: $file->existing; } if ($file->doesntExist()) { // This is an instance of UploadedFile: $file->upload; } })}
Spatie Media Library
The FilePond integration has built-in support for Spatie's Media Library package. The ExampleFile
class has a helper method to load media collections. Instead of loading a collection, it also works with the getFirstMedia()
method.
ExistingFile::fromMediaLibrary($model->getMedia());
Additionally, you may specify the conversion name that FilePond should use for a preview image. There's also support for customizing the expiration and options of the Temporary URL (S3 disk only).
ExistingFile::fromMediaLibrary( media: $model->getMedia(), previewConversionName: 'thumb', previewUrlExpiration: now()->addMinutes(15), previewUrlOptions: ['ResponseContentType' => 'application/octet-stream']);
Instead of using the orderedSpladeFileUploads()
method and syncing the media collection, you may use the syncMediaLibrary
method. This method will add and delete files and set the order. You must pass the Request
instance, the Eloquent model that interacts with media (the subject), and the request key containing the files.
public function update(Request $request){ $user = $request->user(); HandleSpladeFileUploads::syncMediaLibrary($request, $user, 'photos');}
Optionally, there's a fourth and fifth argument to customize the name of the media collection and the name of the disk:
HandleSpladeFileUploads::syncMediaLibrary( request: $request, subject: $user, key: 'photos', collectionName: 'photos', diskName: 's3');
Additional helper methods
To help you identify existing files, you may set an array with metadata:
$existingFile->metadata(['id' => $template->id]);
To retrieve the metadata, you may call the getMetadata()
method to get the array, or pass a key to retrieve a value:
$allMetadata = $existingFile->getMetadata(); $id = $existingFile->getMetadata('id');
Splade will automatically serialize Eloquent models and collections, and the metadata will be encrypted before it's passed to the Vue frontend.