Hello. I’ve just implemented a Livewire data table based on the Caleb’s tutorial on Laracasts. Everything works as expected when working with just one model. However I’m stuck trying to apply sorting and searching to a foreign model field.
User model:
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use Notifiable;
use HasRoles;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* Get the user's email verified status.
*
* @param string $value
* @return string
*/
public function getEmailVerifiedAtAttribute($value)
{
if ($value == null) {
return "No";
}
return $value;
}
public function getRoleAttribute()
{
if($this->roles()->count() > 0) {
return $this->roles()->first()->name;
} else {
return "Usuario registrado";
}
}
public static function search($query)
{
return empty($query) ? static::query()
: static::where('name', 'like', '%'.$query.'%')
->orWhere('email', 'like', '%'.$query.'%');
}
}
Tried adding another orWhere() clause to the search() method in some ways. None worked. Now I left just the default ones.
Livewire controller:
namespace App\Http\Livewire\Users;
use Livewire\Component;
use Livewire\WithPagination;
class Table extends Component
{
use WithPagination;
public $perPage;
public $sortField;
public $sortAsc;
public $search;
public function mount()
{
$this->perPage = 10;
$this->sortField = 'name';
$this->sortAsc = true;
$this->search = '';
}
public function sortBy($field)
{
if ($this->sortField === $field) {
$this->sortAsc = ! $this->sortAsc;
} else {
$this->sortAsc = true;
}
$this->sortField = $field;
}
public function updatingPerPage()
{
$this->resetPage();
}
public function render()
{
return view('livewire.users.table', [
'users' => \App\User::search($this->search)
->with('roles')
->orderBy($this->sortField, $this->sortAsc ? 'asc' : 'desc')
->paginate($this->perPage),
]);
}
}
Livewire view:
<div>
<div class="row mb-4">
<div class="col form-inline">
Mostrar
<select wire:model="perPage" class="form-control form-control-sm custom-select custom-select-sm">
<option>10</option>
<option>100</option>
<option>1000</option>
</select>
registros
</div>
<div class="col-sm-3">
<input wire:model="search" class="form-control form-control-sm" type="text" placeholder="Buscar usuarios...">
</div>
</div>
<div class="table-responsive mb-4" >
<div class="table-header">
<table class="table table-sm text-nowrap" role="grid">
<thead>
<tr>
<th width="30%">
<a wire:click.prevent="sortBy('name')" role="button" href="#">
Nombre
@include('partials._sort-icon', ['field' => 'name'])
</a>
</th>
<th width="30%">
<a wire:click.prevent="sortBy('email')" role="button" href="#">
Correo electrónico
@include('partials._sort-icon', ['field' => 'email'])
</a>
</th>
<th width="30%">
<a wire:click.prevent="sortBy('')" role="button" href="#">
Rol
@include('partials._sort-icon', ['field' => ''])
</a>
</th>
<th></th>
</tr>
</thead>
</table>
</div>
<div class="table-body">
<table class="table table-sm table-hover text-nowrap" role="grid">
<tbody>
@foreach ($users as $user)
<tr>
<td width="30%">{{ $user->name }}</td>
<td width="30%">{{ $user->email }}</td>
<td width="30%">{{ $user->role }}</td>
<td>
<form method="POST" action="{!! route('backend.users.user.destroy', $user->id) !!}" accept-charset="UTF-8">
<input name="_method" value="DELETE" type="hidden">
{{ csrf_field() }}
<div class="btn-group btn-group-xs float-right" role="group">
@can('users.show')
<a href="{{ route('backend.users.user.show', $user->id ) }}" class="btn btn-outline-default btn-xs" title="{{ trans('users.show') }}">
<i class=" fas fa-fw fa-eye" aria-hidden="true"></i>
</a>
@endcan
@can('users.edit')
<a href="{{ route('backend.users.user.edit', $user->id ) }}" class="btn btn-outline-default btn-xs" title="{{ trans('users.edit') }}">
<i class=" fas fa-fw fa-pencil-alt" aria-hidden="true"></i>
</a>
@endcan
@can('users.destroy')
<button type="submit" class="btn btn-outline-default btn-xs" title="{{ trans('users.delete') }}" onclick="return confirm("{{ trans('users.confirm_delete') }}")">
<i class=" fas fa-fw fa-trash-alt" aria-hidden="true"></i>
</button>
@endcan
</div>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
<div class="table-footer">
<div class="text-muted">
Showing {{ $users->firstItem() }} to {{ $users->lastItem() }} out of {{ $users->total() }} results
</div>
<div>
{{ $users->links() }}
</div>
</div>
</div>
Tried also some ways to pass an argument to the sortBy() and [‘field’ => ‘’] on the role column. Now I left them with empty strings.
I know, this issue probably is more related to Laravel than Livewire, but I’ll really appreciate any help.
Update:
Solved using the Laravel Query Builder instead of Eloquent.
PD. Caleb, although you still make me suffer from time to time, you really did a great job creating Livewire. Thanks a lot.