As you are paginating your results you should apply the order by on your database query, where your model's accessors are not available.
One solution is to use the Query Builder's ->when(...) method:
public function render()
{
$teachers = Teacher::query()
->when(
$this->sortField === 'full_name',
function ($query) {
$query->orderByRaw("CONCAT(last_name, ', ', title, ' ', first_name) " . $this->sortDirection);
},
function ($query) {
$query->orderBy($this->sortField, $this->sortDirection);
},
)
->paginate(10);
return view('livewire.teachers.teachers-list', [
'teachers' => $teachers,
]);
}
The ->when(...) method checks for a condition and if it is true it runs the first callback, else it runs the second one.
So in this case we check if the sort field is full_name, then we apply a raw ORDER BY clause to the query's underlying SQL. Otherwise we use the regular ->orderBy(...) method.
The in your livewire component, you can use wire:click as you would for the other fields:
<div class="ml-4">
<div class="mb-0 text-dark-75 font-weight-bolder font-size-lg" wire:click="sortBy('full_name')">{{ $teacher->full_name }}</div>
<a class="text-muted font-weight-bold text-hover-primary" href="#">{{ $teacher->email }}</a>
</div>
Note I used the order you mentioned in your post for ordering (CONCAT(last_name, ', ', title, ' ', first_name)) which is different then the order you are rendering in your model's accessor ({$this->first_name} {$this->last_name})
Hooe it is clear and helps somehow.