Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

whoisthisstud's avatar

Issue with passing collection in Livewire

Dang it... this is what I get for waiting so long to move away from 6.x and try to play catch up with 8.x.

I am attempting to pass paginated results from a livewire component into my view, but continue to get the following error:

Livewire\Exceptions\PublicPropertyTypeNotAllowedException
Livewire component's [contacts-table] public property [contacts] must be of type: [numeric, string, array, null, or boolean]. Only protected or private properties can be set as other types because JavaScript doesn't need to access them.

My LW component

namespace App\Http\Livewire;

use App\Models\Contact;
use Livewire\Component;

class ContactsTable extends Component
{
    public $contacts;
    public $pending = true;
    public $search;


    public function render()
    {
    	$this->contacts = Contact::where('is_contacted','!=',$this->pending)
    		->orderBy('created_at','desc')
    		->paginate(10);

        return view('livewire.contacts-table');
    }
}

And in the livewire blade component...

@forelse($contacts as $contact)
...
@empty
@endforelse

In several video tuts of livewire, I see very similar code (just minus the where and orderBy).

Where am I going wrong? TIA

0 likes
9 replies
laracoft's avatar
laracoft
Best Answer
Level 27

@whoisthisstud

try this?

    public function render()
    {
    	$this->contacts = Contact::where('is_contacted','!=',$this->pending)
    		->orderBy('created_at','desc')
    		->paginate(10)
		->items();

        return view('livewire.contacts-table');
    }
1 like
laracoft's avatar

@whoisthisstud I think adding use WithPagination; is the more livewire way (can't imagine I'm using this phrase already...)

whoisthisstud's avatar

Thank you, @laracoft. Worked perfectly.

I've never used items() before, and just tried quickly searching the docs for it to no avail. Would you mind explaining what exactly "items()" does?

Thanks.

laracoft's avatar

@whoisthisstud I will explain how I came to the answer.

And the magic is in

  1. Putting a bookmark to https://laravel.com/api/master/index.html
  2. Search for paginate and click on the first one which refers to eloquent builder
  3. https://laravel.com/api/master/Illuminate/Database/Eloquent/Builder.html#method_paginate it says paginate returns a LengthAwarePaginator type, which is not accepted by livewire
  4. Click on it and go to https://laravel.com/api/master/Illuminate/Contracts/Pagination/LengthAwarePaginator.html
  5. Find the first function that turns LengthAwarePaginator into an array, which is items() :)

I think these 5 points are even more deserving of the best answer... just kidding...

JoakimL's avatar

@whoisthisstud I do not have enough knowledge to know why this matters, but it turns out that the pagination issue is solved if you pass the data directly in the view() function.

If you changed your example from above to the following, Livewire will not throw the error.

namespace App\Http\Livewire;

use App\Models\Contact;
use Livewire\Component;

class ContactsTable extends Component
{
    public $pending = true;
    public $search;


    public function render()
    {
        return view('livewire.contacts-table', [
		'contacts' => Contact::where('is_contacted','!=',$this->pending)
    		->orderBy('created_at','desc')
    		->paginate(10)
	]);
    }
}

Remember to remove "public $contacts"

whoisthisstud's avatar

@joakiml,

I ended up with this.

namespace App\Http\Livewire;

use App\Models\Contact;
use Livewire\Component;
use Livewire\WithPagination;

class ContactsTable extends Component
{
    use WithPagination;

    ....

    protected function componentsQuery()
    {
        $query = Contact::query();

        if ( $this->deleted ) {
            $query = $query->withTrashed();
        }

        $query = $query->where( function( $query ) {
                $query->where( 'name' , 'like' , '%' . $this->search . '%' )
                    ->orWhere( 'phone' , 'like' , '%' . $this->search . '%' )
                    ->orWhere( 'email' , 'like' , '%' . $this->search . '%' )
                    ->orWhere( 'message' , 'like' , '%' . $this->search . '%' )
                    ->orWhere( 'ip_address' , 'like' , '%' . $this->search . '%' );
            })
            ->where( 'is_contacted' , '!=' , $this->pending )
            ->orderBy( 'deleted_at' , 'asc' )
            ->orderBy( 'created_at' , $this->sort );

        $results = $query->paginate( $this->perPage );
	
        return $results;
    }

    public function render()
    {
        return view( 'livewire.contacts-table' , [
            'contacts' => $this->componentsQuery(),
        ]);
    }

}
1 like

Please or to participate in this conversation.