Filters on a list or table in Laravel Livewire

Filters in web development are used to classify or limit data in a list, they are widely used in administrative modules to limit the data in a list. For example, a filter can be used to display only those elements of a data set that meet with certain criteria, such as a specific date or a particular category; we can actually place any type of field; in practice, filters are nothing more than HTML forms with their respective HTML fields; in which requests are usually sent via GET and not POST, since the aim is to classify data and not change any type of data. Let's see how to use them in Livewire.

Filters in Laravel Livewire

In Laravel Livewire, we can easily apply filters to search our lists, thanks to the fact that there is a kind of synchronization or link between the client side and the server, as far as its properties are concerned, this type of operation is very easy to carry out.

These lists can be anything like a table or list structured based on DIVs.

In this article, we are going to start with a model of publications like the following:

class Post extends Model
{
    use HasFactory;
    protected $fillable=['title', 'slug','date','image','text','description','posted','type', 'category_id'];
    protected $casts =[
        'date' => 'datetime'
    ];
    public function category()
    {
        return $this->belongsTo(Category::class);
    }
}

And the typical listing using a pagination:

  <table class="table w-full border">
        <thead class="text-left bg-gray-100 ">
            <tr class="border-b">
                @foreach ($columns as $key => $c)
                    <th>
                        <button wire:click="sort('{{ $key }}')">
                            {{ $c }}
                            @if ($key == $sortColumn)
                                @if ($sortDirection == 'asc')
                                    &uarr;
                                @else
                                    &darr;
                                @endif
                            @endif
                            
                        </button>
                    </th>
                @endforeach
                <th class="p-2">
                    Acciones
                </th>
            </tr>
        </thead>
        <tbody>
            @foreach ($posts as $p)
                <tr class="border-b">
                    <td class="p-2">
                        {{ $p->id }}
                    </td>
                    <td class="p-2">
                        {{ str($p->title)->substr(0, 15) }}
                    </td>
                    <td class="p-2">
                        {{ $p->date }}
                    </td>
                    <td class="p-2">
                        <textarea class="w-48">
                        {{ $p->description }}
                       </textarea>
                    </td>
                    <td class="p-2">
                        {{ $p->posted }}
                    </td>
                    <td class="p-2">
                        {{ $p->type }}
                    </td>
                    <td class="p-2">
                        {{ $p->category->title }}
                    </td>
                    <td class="p-2">
                        <x-jet-nav-link href="{{ route('d-post-edit', $p) }}" class="mr-2">Editar
                        </x-jet-nav-link>
                        <x-jet-danger-button {{-- onclick="confirm('Seguro que deseas eliminar el registro seleccionado?') || event.stopImmediatePropagation()" --}}
                            wire:click="seletedPostToDelete({{ $p }})">
                            Eliminar
                        </x-jet-danger-button>
                    </td>
                </tr>
            @endforeach
        </tbody>
    </table>
    <br>
    {{ $posts->links() }}

To filter data in the component class, we use where conditions, in this case on the type:

if ($this->type) {
    $posts->where('type', $this->type);
}

The category:

if ($this->category_id) {
    $posts->where('category_id', $this->category_id);
}

And if it is posted or not:

if ($this->posted) {
    $posts->where('posted', $this->posted);
}

All are existing model structures and of course, you can customize.

So, our component to get the filtered posts:

The component class:

//***
// filters
public $type;
public $category_id;
public $posted;
//***
public function render()
{
    $posts = Post::where("id", ">=", 1);
    if ($this->type) {
        $posts->where('type', $this->type);
    }
    if ($this->category_id) {
        $posts->where('category_id', $this->category_id);
    }
    if ($this->posted) {
        $posts->where('posted', $this->posted);
    }
    $categories = Category::pluck("title", "id");
    $posts = $posts->paginate(10);
    return view('livewire.dashboard.post.index', compact('posts', 'categories'));
}
//***

Important to note that:

  1. We have one property per filter.
  2. The query to the database to obtain the posts is composed in several steps and it is verified if the filter properties have a value set to apply in the query.

In the view, we place our filters based on the structure we have:

<div class="flex gap-2 mb-2">
 
        <select class="block w-full" wire:model="posted">
            <option value="">{{__("Posted")}}</option>
            <option value="not">No</option>
            <option value="yes">Si</option>
        </select>
 
        <select class="block w-full" wire:model="type">
            <option value="">{{__("Type")}}</option>
            <option value="adverd">adverd</option>
            <option value="post">post</option>
            <option value="course">course</option>
            <option value="movie">movie</option>
        </select>
 
        <select class="block w-full" wire:model="category_id">
            <option value="">{{__("Category")}}</option>
            @foreach ($categories as $i => $c)
                <option value="{{ $i }}">{{ $c }}</option>
            @endforeach
        </select>
 
    </div>
 
    <table class="table w-full border">
//***

At this point, we would have a paginated list, it is interesting to realize that we can use the properties in Livewire in conjunction with the wire:model not only for record management, but also for other purposes as in this case, it would be to apply a filter.

In the end, we will have:

Filtro
Filtro

And with this, we have a simple filter, remember that you can place more fields following the same organization as the one presented in this post; filters are one of the many topics covered in the Laravel Livewire course and book.

- Andrés Cruz

En español
Andrés Cruz

Develop with Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz In Udemy

I agree to receive announcements of interest about this Blog.