I have issue when i go back and forth in browser navigation buttons, my $searchTerm is not updated in component but is updated in URL and input value is updated also for some reason. But $searchTerm when applying query is not updated.
Here is my Livewire component
class Index extends Component
{
use WithPagination, LivewireComponentFeatures, WithConfirmation, AuthorizationTrait;
protected array $queryString = [
'searchTerm' => ['except' => ''],
'sortBy' => ['except' => ''],
'sortDirection' => ['except' => ''],
'filter' => ['except' => ''],
];
public function __construct ()
{
$this->setPolicyClass(UserPolicy::class);
}
public function mount (): void
{
$this->isAbleTo('viewAny', [Auth::user()]);
$this->sortBy = 'name';
$this->sortDirection = 'asc';
$this->perPage = 20;
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
#[On('changeActiveStatus')]
public function changeActiveStatus (User $user): void
{
$this->isAbleTo('update', [$user, session()->get('current_company_session_data')['id']]);
$user->update([
'active' => !$user->active
]);
$this->dispatch('success', [
'message' => __('Successfully updated status to ') . ($user->active ? __('active!') : __('inactive!'))
]);
}
#[On('delete')]
public function delete (User $user): void
{
$this->isAbleTo('delete', [$user, session()->get('current_company_session_data')['id']]);
$user->delete();
$this->dispatch('success', [
'message' => __('Successfully deleted User!')
]);
}
#[On('restore')]
public function restore ($userId): void
{
$this->isAbleTo('restore', [ Auth::user()]);
User::query()->withTrashed()->firstWhere('id', $userId)->restore();
$this->dispatch('success', [
'message' => __('Successfully restored User!')
]);
}
public function render(): view
{
$users = $this->getUsers();
$this->selectedRecords = $users->pluck('id')->toArray();
view()->share(['swal', true, 'tomSelect' => true]);
return view('livewire.admin.users.index', [
'entities' => $users,
]);
}
protected function getUsers()
{
$query = User::query();
$filter = new UserFilter($query);
$filteredQuery = $filter->apply($this->filter ?? []);
return $filteredQuery
->advancedFilter([
'searchTerm' => $this->searchTerm ?? '',
'sortBy' => $this->sortBy,
'sortDirection' => $this->sortDirection
])
->paginate($this->perPage);
}
public function updated($value)
{
dump($value);
}
}
Here is my trait for livewire features
trait LivewireComponentFeatures
{
public array $selected = [];
public bool $selectAll = false;
public array $selectedRecords = [];
public string $searchTerm = '';
public string $sortBy = '';
public string $sortDirection = 'asc';
public int $perPage;
public array $filter = [];
#[NoReturn]
public function sortByDirection($field): void
{
if ($this->sortBy === $field) {
$this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
} else {
$this->sortBy = $field;
$this->sortDirection = 'asc';
}
}
#[NoReturn]
public function deleteSelected (array $model): void
{
$normalizedModel = ucfirst(trim(strtolower($model[0])));
$modelClass = match ($normalizedModel) {
'User' => User::class,
'Company' => Company::class,
'Driver' => Driver::class,
default => false,
};
if (!$modelClass) {
$this->dispatch('model-not-found');
return;
}
$modelClass::query()->whereIn('id', $this->selected)->delete();
$this->dispatch('success-delete');
$this->resetSelectedProperties();
}
public function updatedSelectAll ($value): void
{
$value ? $this->selected = $this->selectedRecords : $this->selected = [];
}
#[NoReturn]
public function updatedPage ($page): void
{
$this->resetSelectedProperties();
}
#[NoReturn]
public function resetSelectedProperties (): void
{
$this->selected = [];
$this->selectAll = false;
$this->selectedRecords = [];
}
}
Here is my view
<div>
<div wire:ignore id="success-dismissible" class="bg-success dismissible text-sm text-white rounded-md p-4 flex justify-between items-center fixed top-[30px] right-[20px] z-50 hidden">
<p>
<span class="font-medium">Alert:</span>
You can dismiss this alert by, simply click on close button
</p>
<button class="flex-shrink-0 close-dismissible" data-fc-dismiss="dismiss-example" type="button">
<i class="mgc_close_line text-xl close-dismissible"></i>
</button>
</div>
<div class="card grid grid-cols-1">
<div class="card-header">
<div class="flex justify-between items-center">
<h4 class="card-title">@lang('Users')</h4>
<a href="{{ route('users.create') }}" type="button" class="btn rounded-full border border-success text-success hover:bg-success hover:text-white text-14-px sm:text-16-px">@lang('Create User')</a>
</div>
</div>
<div class="p-6">
<div class="overflow-x-auto">
<div class="min-w-full inline-block align-middle">
<div class="border rounded-lg divide-y divide-gray-200 dark:border-gray-700 dark:divide-gray-700">
<div class="flex flex-row items-center gap-2 py-3 px-4">
<div class="relative max-w-225-px w-full">
<label for="table-with-pagination-search" class="sr-only">@lang('Search')</label>
<input wire:model.live.debounce.300ms="searchTerm" id="table-with-pagination-search" class="form-input ps-11" type="text" name="table-with-pagination-search" placeholder="Search for users">
<div class="absolute inset-y-0 start-0 flex items-center pointer-events-none ps-4">
<svg class="h-3.5 w-3.5 text-gray-400" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewbox="0 0 16 16">
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"></path>
</svg>
</div>
</div>
<div class="w-full max-w-200-px">
<div wire:ignore>
<select id="company-select" data-route="{{ route('companies.selection') }}" wire:model.live="filter.company" name="filter[company]" class="tom-select company-select form-input w-full max-w-200-px bg-white text-gray-900 dark:bg-gray-800 dark:text-gray-100 border border-gray-300 dark:border-gray-700 rounded-md p-2 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400"></select>
</div>
<x-form-inputs.error :messages="$errors->get('form.companies')" />
</div>
<div class="w-full max-w-200-px">
<div wire:ignore>
<select id="role-select" data-route="{{ route('roles.selection') }}" wire:model.live="filter.role" name="filter[role]" class="tom-select role-select w-full bg-white max-w-200-px text-gray-900 dark:bg-gray-800 dark:text-gray-100 border border-gray-300 dark:border-gray-700 rounded-md p-2 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400"></select>
</div>
</div>
<div class="relative max-w-100-px w-full {{ $selected ? '' : 'hidden' }}">
<button wire:click="confirm('deleteSelected', 'User')" type="button" class="btn border-danger text-danger hover:bg-danger hover:text-white" wire:loading.attr="disabled" {{ $selected ? '' : 'disabled' }}>@lang('Delete All')</button>
</div>
</div>
<div class="overflow-hidden">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead class="bg-gray-50 dark:bg-gray-700">
<tr>
<th scope="col" class="py-3 px-4 pe-0">
<div class="flex items-center h-5">
<input wire:model.live="selectAll" id="table-pagination-checkbox-all" class="form-checkbox rounded" type="checkbox" >
<label for="table-pagination-checkbox-all" class="sr-only">@lang('Checkbox')</label>
</div>
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
<div class="flex flex-row items-center">
@lang('Name')
<x-includes.sort :sortBy="$sortBy" :sortDirection="$sortDirection" field="name" />
</div>
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
<div class="flex flex-row items-center">
@lang('Email')
<x-includes.sort :sortBy="$sortBy" :sortDirection="$sortDirection" field="email" />
</div>
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
<div class="flex flex-row items-center">
@lang('Company')
<x-includes.sort :sortBy="$sortBy" :sortDirection="$sortDirection" field="companies.name" />
</div>
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
<div class="flex flex-row items-center">
@lang('Role')
<x-includes.sort :sortBy="$sortBy" :sortDirection="$sortDirection" field="roles.name" />
</div>
</th>
<th scope="col" class="px-6 py-3 text-end text-xs font-medium text-gray-500 uppercase">
@lang('Actions')
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@foreach($entities as $entity)
<tr>
<td class="py-3 ps-4">
<div class="flex items-center h-5">
<input wire:model.live="selected" id="table-pagination-checkbox-1" type="checkbox" class="form-checkbox rounded" value="{{ $entity->id }}">
<label for="table-pagination-checkbox-1" class="sr-only">@lang('Checkbox')</label>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200">
{{ $entity->name }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200">
{{ $entity->email }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200">
@if ($entity->companies->isNotEmpty())
@foreach ($entity->companies as $company)
<span class="text-sm">{{ $company->name }}</span>{{ $loop->last ? '' : ', ' }}
@endforeach
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-200">
{{ $entity->roles->first()?->name }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-end text-sm font-medium">
<x-buttons.view :entity="$entity" :route="route('users.show', ['user' => $entity->slug])" />
<x-buttons.edit :entity="$entity" :route="route('users.edit', ['user' => $entity->slug])" />
<x-buttons.active :entity="$entity" />
<x-buttons.delete :entity="$entity" />
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="py-1 px-4">
{{ $entities->links() }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@push('script')
<script type="text/javascript">
document.addEventListener('livewire:init', () => {
// Confirm
Livewire.on('confirm', (e) => {
handleConfirmation(e[0].callback, e[0].argv);
});
// Model Not Found
Livewire.on('model-not-found', () => {
Swal.fire({
title: 'Model not found!',
icon: 'error',
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok'
});
});
const tomSelectElements = document.querySelectorAll('.tom-select');
if (tomSelectElements) {
tomSelectElements.forEach(tomSelectElement => {
let placeholder = tomSelectElement.id === 'role-select' ? 'Select the role' : 'Select the company';
const dataRoute = tomSelectElement.getAttribute('data-route');
const loadOptions = (query, callback) => {
axios.post(dataRoute, { term: query })
.then(response => {
const entities = response.data.data;
const options = entities.map(entity => ({
value: entity.id,
text: entity.selection.text
}));
callback(options);
})
.catch(error => {
console.error(error);
callback();
});
};
new TomSelect(tomSelectElement, {
placeholder: placeholder,
create: false,
load: loadOptions,
sortField: {
field: "text",
direction: "asc"
},
plugins: ['remove_button'],
onInitialize: function() {
this.on('focus', () => {
loadOptions('', options => {
this.clearOptions();
this.addOptions(options);
this.refreshOptions(false);
this.open();
});
});
},
});
})
}
});
function handleConfirmation(callback, argv) {
const confirmationOptions = {
title: 'Are you sure?',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
reverseButtons: true
};
switch (callback) {
case 'delete':
confirmationOptions.confirmButtonText = 'Yes, delete it!';
break;
case 'restore':
confirmationOptions.confirmButtonText = 'Yes, restore it!';
break;
case 'changeActiveStatus':
confirmationOptions.confirmButtonText = 'Yes, change it!';
break;
default:
break;
}
Swal.fire(confirmationOptions).then((result) => {
if (result.isConfirmed) {
@this[callback](argv);
Livewire.on(`success`, (e) => {
const successDismissible = document.getElementById('success-dismissible');
successDismissible.querySelector('p').textContent = e[0].message;
successDismissible.classList.remove('hidden');
setTimeout(() => {
successDismissible.classList.add('hidden');
}, 5000);
});
}
});
}
</script>
@endpush
I have tried hydrated(), updated() — on property and general updated(), I have tried #[Url*…],
I have tried via javascript. Nothing seems to be working