Livewire File Upload with Preview: Tips and Best Practices - Programming Fields (2024)

Livewire file upload in Laravel refers to the process of allowing users to upload files using the Livewire framework. Allowing users to upload files is a common requirement. Whether it’s for sharing images, documents, or media files, handling file uploads effectively is very important. It is crucial to follow best practices when implementing file uploads to ensure a smooth and secure user experience. Livewire is a powerful framework that allows developers to build interactive web interfaces using Laravel. It provides a seamless way to handle file upload by leveraging its real-time communication capabilities. In this blog post, we’ll explore some practical tips and best practices for managing file upload using Livewire in Laravel.

Before moving to the example, let’s quickly recap what we are going to achieve today.

Livewire File Upload with Preview: Tips and Best Practices - Programming Fields (1)

In the above form, we have a file input along with two text input fields.

Livewire File Upload with Preview: Tips and Best Practices - Programming Fields (2)

Also, we have the real-time validation using the Livewire. We will be working on the interesting feature of livewire which is file preview.

Yes, Livewire provides a preview option for the uploaded image. So, in the below result, when you select the image, it will be previewed before upload. After that you can submit the form.

Livewire File Upload with Preview: Tips and Best Practices - Programming Fields (3)

After filling above details, when I submit the form, it will be submitted. Also, the image will be uploaded and the details will be stored in the database.

Livewire File Upload with Preview: Tips and Best Practices - Programming Fields (4)

Let’s come to the example now.

Table of Contents

Step 1 – Preparing Your Environment For Livewire File Upload

To start using Livewire for file upload in Laravel, you need to install and set up both Livewire and Laravel.

Hence, let’s start first with the Laravel project setup. So, open the terminal and hit the below command to install Laravel.

composer create-project --prefer-dist laravel/laravel livewire-file-upload

Once installed, you can configure the database for the project. So, open the project in any of your editors. Thereafter, come inside the .env file and add the DB configuration.

DB_CONNECTION=mysqlDB_HOST=127.0.0.1DB_PORT=3306DB_DATABASE={{DATABASE_NAME}}DB_USERNAME={{DATABASE_USERNAME}}DB_PASSWORD={{DATABASE_PASSWORD}}

After the DB configuration, we will move out the Livewire installation in the current Laravel project.

composer require livewire/livewire

Now, you are done with the Livewire and Laravel setup. Hence, let’s move to the next step.

Recommended: Livewire Pagination in Laravel: Making Your App Dynamic and Responsive

Step 2 – Model and Migration Setup For File Upload in Livewire

You need a model and migration for creating the user profile section as per the result. You can create it for the User. However, Laravel has the default User model and migration. Hence, I will be using the same one.

But, you need to update the migration as shown below.

<?phpuse Illuminate\Database\Migrations\Migration;use Illuminate\Database\Schema\Blueprint;use Illuminate\Support\Facades\Schema;return new class extends Migration{ /** * Run the migrations. */ public function up(): void { Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('email')->unique(); $table->string('profile_image'); $table->string('profile_image_original'); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('users'); }};

For this migration, you will have to modify the fillable data in the User model.

<?phpnamespace App\Models;// use Illuminate\Contracts\Auth\MustVerifyEmail;use Illuminate\Database\Eloquent\Factories\HasFactory;use Illuminate\Foundation\Auth\User as Authenticatable;use Illuminate\Notifications\Notifiable;use Laravel\Sanctum\HasApiTokens;class User extends Authenticatable{ use HasApiTokens, HasFactory, Notifiable; /** * The attributes that are mass assignable. * * @var array<int, string> */ protected $fillable = [ 'name', 'email', 'profile_image', 'profile_image_original' ];}

After that, you will have to migrate the schema using the migrate command.

php artisan migrate

Step 3 – Create Livewire Component For File Upload

Creating a file upload component is a fundamental step in Livewire. By implementing file upload functionality, users can select and upload files. It is crucial to validate and store the uploaded files securely to maintain data integrity.

Hence, firstly, you will have to create a Livewire component using the below command.

php artisan make:livewire UserProfile

This command will generate a component having a class and a view file.

In the view file, you will have to design a basic file upload form. So, let’s do that quickly.

Recommended: Building a Dynamic Livewire CRUD Application in Laravel 10

Step 4 – Design User Interface For File Upload in Livewire

The component view file will be located in the resources/views/livewire directory. Hence, open it and add the below snippet.

<div class="container my-2"> <div class="row"> <div class="col-xl-6 m-auto"> {{-- Display flash message --}} @if (session()->has('success')) <div class="alert alert-success alert-dismissible fade show"> <svg class="bi flex-shrink-0 me-2" width="24" height="24" role="img" aria-label="Success:"> <use xlink:href="#check-circle-fill" /> </svg> <strong>Success!</strong> {{ session('success') }} <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> </div> @elseif (session()->has('error')) <div class="alert alert-danger alert-dismissible fade show"> <svg class="bi flex-shrink-0 me-2" width="24" height="24" role="img" aria-label="Danger:"> <use xlink:href="#exclamation-triangle-fill" /> </svg> <strong>Alert!</strong> {{ session('error') }} <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> </div> @endif {{-- form starts --}} <form wire:submit.prevent="submitForm"> <div class="card shadow"> <div class="card-header"> <h5 class="card-title fw-bold">User Profile </h5> </div> <div class="card-body px-5"> {{-- profile image --}} <div class="form-group text-center "> <div class="position-relative"> <label for="profileImage" class="profile-image-label"> {{-- if profile image selected then preview --}} @if ($profileImage) <img src="{{ $profileImage->temporaryUrl() }}" width="60" height="60" class="img-fluid profile-img" /> @else {{-- show default icon --}} <span class="img-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 24 24"> <circle cx="12" cy="12" r="3.2" /> <path d="M9 2l-1.83 2h-3.17c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-12c0-1.1-.9-2-2-2h-3.17l-1.83-2h-6zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5z" /> <path d="M0 0h24v24h-24z" fill="none" /> </svg> </span> @endif <input type="file" id="profileImage" wire:model="profileImage" class="file-input" name="profileImage" /> </label> </div> {{-- Display message validation error message --}} <div> @error('profileImage') <span id="message-error" class="text-danger">{{ $message }}</span> @enderror </div> </div> {{-- name --}} <div class="form-group"> <label for="name">Name <span class="text-danger">*</span></label> <input type="text" id="name" wire:model="name" placeholder="Name" aria-describedby="name-error" aria-required="true" @error('name') aria-invalid="true" @enderror class="form-control @error('name') is-invalid @enderror"> {{-- Display name validation error message --}} @error('name') <span id="name-error" class="text-danger">{{ $message }}</span> @enderror </div> {{-- email --}} <div class="form-group my-3"> <label for="email">Email <span class="text-danger">*</span></label> <input type="text" id="email" wire:model="email" placeholder="Email" aria-describedby="email-error" @error('email') aria-invalid="true" @enderror class="form-control @error('email') is-invalid @enderror"> {{-- Display email validation error message --}} @error('email') <span id="email-error" class="text-danger">{{ $message }}</span> @enderror </div> <div class="form-group mb-2"> <button type="submit" class="btn btn-primary">Submit</button> </div> </div> </div> </form> {{-- form ends --}} </div> </div></div>

Livewire file modeling is similar to the other input binding model. It doesn’t require form attribute enctype=”multipart/form-data” for reading file from the form as Laravel requires.

So, let’ see how you can read and handle file uploading in Livewire.

Step 5 – Implement File Upload Functionality in Livewire

Livewire provides a Trait for file upload handling. It needs to import at the top and then this can be used in the component to read the file from the Form.

use WithFileUploads;

Let’s add this Trait to handle the file upload in Livewire component.

<?phpnamespace App\Http\Livewire;use App\Models\User;use Livewire\Component;use Livewire\WithFileUploads;class UserProfile extends Component{ // use livewire trait use WithFileUploads; // Define public attributes public $name, $email, $profileImage; // Component Rendering public function render() { return view('livewire.user-profile'); } // Define validation rules protected $rules = [ 'name' => 'required', 'email' => 'required|email', 'profileImage' => 'required|image|max:2048' ]; // Define custom validation error message protected $messages = [ 'name.required' => 'Name is required', 'email.required' => 'Email address is required', 'email.email' => 'Email address is not valid', 'profileImage.required' => 'Profile image is required', 'profileImage.image' => 'Profile image is not valid', 'profileImage.image.max' => 'Profile image size is too large', ]; // Validate inputs in realtime public function updated($inputNames) { $this->validateOnly($inputNames); } /** * Function : Submit Form * @param NA * @return response */ public function submitForm() { // Validate form $validatedInputs = $this->validate(); // Store profile image in user-profile directory $this->profileImage->store('user-profile'); $validatedInputs['profile_image'] = $this->profileImage->getFilename(); $validatedInputs['profile_image_original'] = $this->profileImage->getClientOriginalName(); $user = User::create($validatedInputs); // Reset form inputs $this->resetInputs(); if ($user) { session()->flash('success', 'User Profile details saved successfully!'); } else { session()->flash('error', 'Unable to save User Profile. Please try again!'); } } // Reset form inputs private function resetInputs() { $this->name = null; $this->email = null; $this->profileImage = null; }}

Let me explain what I have done In the above snippet.

  • I have used the Livewire trait at the beginning.
  • After that, I created public variables to bind form inputs.
  • Next, I created the validation rules and the custom validation error messages.
  • Then we have the submit form function to handle the form submit request. Initially, the form submit request will validate the inputs including the uploaded file. Then we store the profile image in the storage directory.
  • Lastly, we are saving these records into the users table and returning the flash message.

Now, this component needs to be called in a blade file to be executed. So, let’s create a Laravel blade file.

Recommended: Livewire Form Validation: Building Better User Experiences in Laravel

Step 6 – Render Livewire Component

In this step, you will require a controller and a blade file. So, let’s have a controller first.

php artisan make:controller UserController

After having the controller, let’s add the below snippet to render a blade file.

<?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;class UserController extends Controller{ public function userProfile() { return view('user'); }}

After that, you need to create a blade file. So, create a blade file by giving the name user.blade.php.

<!doctype html><html lang="en"><head> <title>Livewire File Upload in Laravel 10</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> {{-- Bootstrap CSS v5.2.1 --}} <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT" crossorigin="anonymous"> {{-- Livewire Styles --}} @livewireStyles {{-- Custom CSS --}} <style> .file-input::-webkit-file-upload-button { visibility: hidden; } input[type='file'] { font-size: 10px; margin-left: 60px } ::file-selector-button { font-size: initial; } .file-input::before { content: ''; display: inline-block; height: 150px; width: 150px; border: 1px solid #999; border-radius: 50%; padding: 5px 8px; outline: none; white-space: nowrap; -webkit-user-select: none; cursor: pointer; text-shadow: 1px 1px #fff; font-weight: 700; font-size: 10pt; } .file-input:hover::before { border-color: black; } .file-input:active::before { background: -webkit-linear-gradient(top, #e3e3e3, #f9f9f9); } .img-icon { margin-left: 104px; cursor: pointer; position: absolute; top: 45px; bottom: 0; } .profile-img { height: 150px; width: 150px; position: absolute; cursor: pointer; border-radius: 50%; margin-left: 60px } </style></head><body> <main class="pt-3 px-5"> <div class="container-fluid"> <h3 class="text-center fw-bold border-bottom pb-2">Livewire File Upload with Preview in Laravel </h3> <div class="row justify-content-center mt-3"> {{-- Calling Livewire Component --}} @livewire('user-profile') </div> </div> </main> {{-- jQuery CDN --}} <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> {{-- Bootstrap JavaScript Libraries --}} <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.min.js"></script> {{-- Livewire Scripts --}} @livewireScripts</body></html>

That’s done for the Livewire file upload. However, you need a route for rendering this demo application. Therefore, let’s add this.

Step 7 – Route Binding for Livewire File Upload

In order to add the route, you will have to navigate to the web.php file and add the below snippet.

<?phpuse App\Http\Controllers\UserController;use Illuminate\Support\Facades\Route;Route::get('user-profile', [UserController::class, 'userProfile'])->name('user-profile');

That’s it now, you can run the application to see the result.

Conclusion

In this example, we explored how to implement Livewire file upload in Laravel. We created a Livewire component for handling file upload built a Blade view for the component, and added it to a route. Livewire simplifies the process of creating interactive components, making it easier to handle file upload and other user interactions in your Laravel applications. Feel free to adapt this example to suit your specific requirements, such as custom validation rules or additional file handling logic. You can Improve user experience during file uploads involves implementing progress bars and notifications. This provides users with visual feedback on the upload progress. Allowing users to cancel or retry file uploads gives them more control over the process. Providing visual feedback for completed uploads ensures users are aware of the successful upload. We will see these all advanced file upload guides in upcoming post.

Related

Livewire File Upload with Preview: Tips and Best Practices - Programming Fields (2024)

References

Top Articles
Latest Posts
Article information

Author: Madonna Wisozk

Last Updated:

Views: 6652

Rating: 4.8 / 5 (48 voted)

Reviews: 95% of readers found this page helpful

Author information

Name: Madonna Wisozk

Birthday: 2001-02-23

Address: 656 Gerhold Summit, Sidneyberg, FL 78179-2512

Phone: +6742282696652

Job: Customer Banking Liaison

Hobby: Flower arranging, Yo-yoing, Tai chi, Rowing, Macrame, Urban exploration, Knife making

Introduction: My name is Madonna Wisozk, I am a attractive, healthy, thoughtful, faithful, open, vivacious, zany person who loves writing and wants to share my knowledge and understanding with you.