Filtros sobre un listado o tabla en Laravel Livewire

- Andrés Cruz

In english
Filtros sobre un listado o tabla en Laravel Livewire

Los filtros en el desarrollo web se utilizan para clasificar o limitar datos en algun listado, son muy utilizados en los módulos administrativos para limitar los datos de un listado Por ejemplo, un filtro puede utilizarse para mostrar solo aquellos elementos de un conjunto de datos que cumplan con ciertos criterios, como una fecha específica o una categoría en particular; realmente podemos colocar cualquier tipo de campo; en la práctica, los filtros no son más que formularios HTML con sus respectivos campos en HTML; en el cual, usualmente se envían peticiones vía GET y no POST, ya que, se busca es clasifcar datos y no cambiar ningún tipo de dato. Veamos como usarlos en Livewire.

Los filtros en Laravel Livewire

En Laravel Livewire, podemos aplicar filtros fácilmente para búsqueda en nuestros listados, gracias a que existe una especie de sincronización o lazo entre el lado del cliente con el servidor, a lo que a sus propiedades se refiere, este tipo de operación resultan muy fáciles de realizar.

Estos listados pueden ser cualquier cosa como una tabla o lista estructuradas en base a DIVs.

En este artículo, vamos a partir de un modelo de publicaciones como el siguiente:

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);
    }
}

y el listado típico usando una paginación:

  <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() }}

Para filtrar datos en la clase componente, usamos condiciones where, en este caso sobre el tipo:

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

La categoría:

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

Y si esta posteado o no:

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

Todas son estructuras modelos existentes y que por supuesto, puedes personalizar.

Así que, nuestro componente para obtener los post filtrados:

La clase componente:

//***
// 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'));
}
//***

Importante notar que:

  • Tenemos una propiedad por filtro.
  • Se compone la consulta a la base de datos para obtener los posts en varios pasos y se verifica si las propiedades filtros tienen un valor establecido para aplicar en la consulta.

En la vista, colocamos nuestros filtros en base a la estructura que tengamos:

<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">
//***

Ya en este punto, tendríamos un listado paginado, es interesante darse cuenta que podemos usar las propiedades en Livewire en conjunto con los wire:model no solamente para la gestión de registros, si no también para otros propósitos como en este caso, sería aplicar un filtro.

Al final, tendremos:

Filtro
Filtro

Y con esto, tenemos un sencillo filtro, recuerda que puedes colocar más campos siguiente la misma organización que la presentada en esta entrada; los filtros son unos de los muchos temas que tratamos en el curso y libro sobre Laravel Livewire.

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz en Udemy

Acepto recibir anuncios de interes sobre este Blog.