JohnnyBigodes's avatar

[Livewire] Search doesnt work after pagination

Hello everyone,

I have a search in Livewire that it doesnt work unless the pagination in on page 1.

Here is my class:

<?php

namespace App\Http\Livewire\Tags;

use App\Tag;
use Exception;
use Illuminate\Contracts\View\Factory;
use Illuminate\View\View;
use Livewire\Component;
use Livewire\WithPagination;

class TagEdit extends Component
{
    use WithPagination;

    public $searchInput;
    protected $searchList;
    protected $pagination = 5;

    /**
     * @param $id
     * @throws Exception
     */
    public function deleteTags($id): void
    {
        $deleteID = Tag::findOrFail($id);
        $deleteID->delete();
    }

    /**
     * @return Factory|View
     */
    public function render()
    {
        $this->searchList = Tag::where('schlagwort', 'like', '%' . $this->searchInput . '%')
            ->orderBy('created_at', 'desc')
            ->paginate($this->pagination);

        return view('livewire.tags.tag-edit', [
            'searchList' => $this->searchList,
        ]);
    }
}

And here is my view:

<div>
    <div class="text-left mb-5">
        <label for="labelSchlagwort" class="font-weight-bold">Schlagwort Suchen:</label>
        <input class="form-control" placeholder="Schlagwort Suchen" type="text" wire:model="searchInput">
    </div>

    @if($searchList->total() > 0)
        {{ $searchList->links() }}
        <table class="table table-striped table-hover">
            <thead>
            <tr>
                <th scope="col" class="text-left">Schlagwort</th>
                <th scope="col" class="text-left">Angelegt am</th>
                <th scope="col" class="text-left"></th>
            </tr>
            </thead>
            <tbody>
            @foreach($searchList as $searchedItem)
                <tr>
                    <td class="text-left">{{ $searchedItem->schlagwort }}</td>
                    <td class="text-left">{{ $searchedItem->created_at }}</td>
                    <td class="text-left">
                        <button class="btn btn-success">Editieren</button>
                        <button class="btn btn-danger" wire:click="deleteTags({{ $searchedItem->id }})">Löschen</button>
                    </td>
                </tr>
            @endforeach
            </tbody>
        </table>
        {{ $searchList->links() }}
    @endif
</div>

The search only works if the pagination is on the #1.

It seems I cant fix it and am trying to get your help.

Thank you in advance

EDIT: Seems that the search works, but somehow it still shows the pagination even when the result count is smaller than 5.

Here is a video of the behaviour: https://youtu.be/uWFiGDlw7cg

0 likes
8 replies
Snapey's avatar

Non-livewire way is to append the search term to the links. I assume it works the same?

$this->searchList = Tag::where('schlagwort', 'like', '%' . $this->searchInput . '%')
            ->orderBy('created_at', 'desc')
            ->paginate($this->pagination)
            ->appends('searchInput', $this->searchInput);

JohnnyBigodes's avatar

I tried the appends and still doesnt work.

For some reason the Pagination is still showing, even when the result count is lower than 5.

If I search for something and after a search I click on the pagination my results get shown, but I dont think this is the way it should be.

Here is how it works: https://youtu.be/uWFiGDlw7cg (Take a look at 0:32)

mstrauss's avatar

@johnnybigodes

I think I see what's happening here. It's not really a live wire thing, it looks like a Laravel Core pagination issue. Take a look at the below method from the Laravel Framework:

    /**
     * Determine if there are enough items to split into multiple pages.
     *
     * @return bool
     */
    public function hasPages()
    {
        return $this->currentPage() != 1 || $this->hasMorePages();
    }

The first part of the OR statement says that if the currentPage is not equal to one (1) then the pagination links should be present. In your YouTube video, it appears that the pagination links only show when you search after clicking on a page link other than one. I'm going to look at this more deeply as a PR to the Laravel framework may be needed to fix the issue.

EDIT

On a second look at the Laravel Framework's history, the method above was last updated by Taylor Otwell on Dec 20, 2016, so that is unlikely to be the issue. Maybe it is the LiveWire implementation.

https://github.com/laravel/framework/commit/379afab27bbdf407d2cd9619e8c42204c4049a37#diff-7cfe0444379b67f9dedf780bf9ec3f3a

JohnnyBigodes's avatar

Yes, this could also be a Laravel issue and not a specific Livewire issue.

Let me know if you want me to create an issue for the Laravel Framework.

mstrauss's avatar

@johnnybigodes

Out of curiosity, if you do not use the livewire-pagination hook, do you experience the same issue?

Snapey's avatar

Out of interest, why do you save searchList as a protected class attribute?

JohnnyBigodes's avatar

@mstrauss

Yes, i am using the Livewire pagination for that.

@snapey

That was just testing some things I have never done. ;oD

Normaly it looks like this:

        return view('livewire.tags.tag-edit', [
            'searchList' => Tag::where('schlagwort', 'like', '%' . $this->searchInput . '%')
            ->orderBy('created_at', 'desc')
            ->paginate($this->pagination),
        ]);
JohnnyBigodes's avatar
JohnnyBigodes
OP
Best Answer
Level 13

I just wanted to write how I have fixed this.

The problem is, that Livewire keeps the state of your pagination even when you update your component.

The search works flawlessly when you are on page 1.

If you are on a page other than 1 your url state is still perserved and so the search wont work.

For this to work you have to set a lifecycle hook when updating your public property, so that you can set it everytime to page 1.

If you do that everything will work without a problem.

Controller:

<?php

namespace App\Http\Livewire\Tags;

use App\Tag;
use Exception;
use Illuminate\Contracts\View\Factory;
use Illuminate\View\View;
use Livewire\Component;
use Livewire\WithPagination;

class TagEdit extends Component
{
    use WithPagination;

    public $searchInput;
    private $pagination = 5;

    /**
     * @param $id
     * @throws Exception
     */
    public function deleteTags($id): void
    {
        $deleteID = Tag::findOrFail($id);
        $deleteID->delete();
    }

    /**
     *  Livewire Lifecycle Hook
     */
    public function updatingSearchInput(): void
    {
        $this->gotoPage(1);
    }

    /**
     * @return Factory|View
     */
    public function render()
    {
        return view('livewire.tags.tag-edit', [
            'searchList' => Tag::where('schlagwort', 'like', '%' . trim($this->searchInput) . '%')
                ->orderBy('created_at', 'desc')->paginate($this->pagination),
        ]);
    }
}

View:

<div xmlns:wire="http://www.w3.org/1999/xhtml">
    <div class="text-left mb-5">
        <label for="labelSchlagwort" class="font-weight-bold">Schlagwort Suchen:</label>
        <input class="form-control" placeholder="Schlagwort Suchen" type="text" wire:model="searchInput">
    </div>

    @if($searchList->total() > 0)
        <div class="container">
            {{ $searchList->links() }}
            <table class="table table-striped table-hover">
                <thead>
                <tr>
                    <th scope="col" class="text-left">Schlagwort</th>
                    <th scope="col" class="text-left">Angelegt am</th>
                    <th scope="col" class="text-left"></th>
                </tr>
                </thead>
                <tbody>
                @foreach($searchList as $searchedItem)
                    <tr>
                        <td class="text-left">{{ $searchedItem->schlagwort }}</td>
                        <td class="text-left">{{ $searchedItem->created_at }}</td>
                        <td class="text-left">
                            <button class="btn btn-success">Editieren</button>
                            <button class="btn btn-danger" wire:click="deleteTags({{ $searchedItem->id }})">
                                Löschen
                            </button>
                        </td>
                    </tr>
                @endforeach
                </tbody>
            </table>
            {{ $searchList->links() }}
        </div>
    @endif

</div>

Hope this helps other people that are having the same issue.

11 likes

Please or to participate in this conversation.