ethump's avatar

Pagination

Hi Team,

Kinda new to Laravel and even newer to Livewire. I'm working to build out an application and loving the journey so far. Really enjoying Laravel!

Before I 'discovered' Livewire pagination, I was producing a very large HTML table based on a MySQL table. In its simplest form, I was just doing $things=Things::get(); passing $things to the blade and then iterating through $things as $thing and producing that honking great HTML table.

I found Livewire pagination and was quickly able to implement it by doing Things::paginate() and the other stuff and it works just dandy.

As my app developed, I wanted to enrich that table. 'Things' have owners (represented on the things table as an owner ID). The 'owners' table has the full ID, Name, email, phone# etc. I want some of that reference data including on the HTML table.

Before Livewire pagination, in the controller, I'd slurp in the entire 'things' table to $things and 'owners' table into $owners. Then, I'd build a new array by iterating through $things in an outer loop and then through owners until there's a match on the id field. Idea being that the resulting array would have something like:

$resultingArray['0']['thingName']="small widget"; $resultingArray['0']['owner']="Fred Smith"; $resultingArray['1']['thingName']="big widget"; $resultingArray['1']['owner']="Sarah Jones";

I pass $resultingArray to the blade and produce the table from there. Hope I'm making sense so far.

My question is: How do I use Livewire pagination on this resulting array - or elsewise achieve same?

I've tried Googleing for and answer but I'm not sure I'm getting my search terms right. Hopefully, by being a bit more expressive here, I'm getting my question across!

My guess is that I need to use Eloquent ORM to do the joining replicating that $resultingArray and then sticking paginate() on the end? Figured I'd ask quickly here if I'd be on the right track before investing time learning all that. Or am I missing something!?

cheers all!

0 likes
18 replies
franklinIwobi's avatar

Why not use Eloquent Relationships?

//thing model
class Thing
{
    public function owner() : BelongsTo 
    {
        return $this->belongsTo(Owner::class);
    }
}

//owner model
class Owner
{
    public function things() : HasMAny 
    {
        return $this->hasMany(Thing::class);
    }
}

//livewire component
#[Computed]
public function things()
{
    return Thing::with('owner')->paginate(20);
}

//livewire blade file
@foreach($this->things as $thing)
{
    <li>{{ $thing->name }}</li>
    <li>{{ $thing->owner->name }}</li>
}

Hope this helps 🙂

2 likes
ethump's avatar

@franklinIwobi cos I'm new to this and don't have too much of a clue what I'm doing! thanks for the response, will try digest what you're telling me!

franklinIwobi's avatar

@ethump Remember that for the above code to work, you need to have a database schema that looks like this

//create_owners_table
public function up(): void
{
    Schema::create('owners', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        //other fields
        $table->timestamps();
    });
}

//create_things_table
public function up(): void
{
    Schema::create('things', function (Blueprint $table) {
        $table->id();
        $table->foreignId('user_id')->constrained()->cascadeOnDelete();
        $table->string('name');
        //other fields
        $table->timestamps();
    });
}
1 like
franklinIwobi's avatar

*edit

//create_things_table
public function up(): void
{
    Schema::create('things', function (Blueprint $table) {
        $table->id();
        $table->foreignId('owner_id')->constrained()->cascadeOnDelete();
        $table->string('name');
        //other fields
        $table->timestamps();
    });
}
ethump's avatar

@franklinIwobi Thanks again. Late here will look over what you've explained in due course. At first glance, I think it makes sense, cheers!

Snapey's avatar

do this in the render method, and pass to the view, not as a public property

You can then gather things with owners and iterate over the data server side with all the formatting done in blade

@foreach($things as $thing)
<tr>
		<td>{{ $thing->name }}</td>
		<td>{{ $thing->owner->name }}</td>
		<td>{{ $thing->owner->email }}</td>
etc

<tr>
@endforeach
ethump's avatar

So I've merged this into my main code for my app and it works. Lets say I have 35 'things' and I'm doing paginate(10).

First time I do this, I see 4 pages on the links with 10, 10, 10 and 5 rows per. As you'd expect.

If I delete a row (call a delete function on the livewire controller - same place where the render method lives), it works, the record deletes in the database, and disappears from the page on the display.

Let's say I delete 2 'things' from the 1st page and 5 from the 2nd page. it doesn't refresh as I'd expect. I still see 4 pages, just with 8,5,10 and 5 things per page. Refreshing the page doesnt help. Even if I log out the app completely and back in again, this remains the view. Indeed, if I delete all 35 'things', I see 4 empty pages. Even after login/out.

I've tried sticking $this->render(); on the delete() method to no avail.

What am I missing? I don't think this is to do with the relationships stuff.

cheers!

Snapey's avatar

@ethump are you behind some cache such as cloudflare?

Even if I log out the app completely and back in again, this remains the view

The data is being cached somewhere. Livewire does not cache so you either have external cache or you have added caching to your model(s)

ethump's avatar

@Snapey Nope. This is plain old served over HTTP by Apache on my home network. Not even crossing a firewall.

Even firing up the php artisan serve dev server behaves same.

ethump's avatar

Oh, and the models are completely default.

protected $fillable = ['name', 'owner_id', 'description'];

Nothing has anything fancy.

Switching machines and even using completely different browser yields same.

Tried using a different user context (within my app)... same.

ethump's avatar

I've worked it out. I was doing something dopey and it totally makes sense why I was seeing the behaviour I was.

The actuality of my app was that I was marking things inactive (via a bool) but only filtering on that when iterating the rows in the blade (@if $thing['active']==1....) The actual DB query just returned all rows (which of course would have been 35 every time). So pretty embarrassing really.. but always learning!

Snapey's avatar

@ethump I've learned that at some point its just best to step back and let you work it out. Hopefully you now have an eloquent scope that you can add to the query.

ethump's avatar

@Snapey Yep - totally appreciate this. And to be fair, you didn't know the larger context of my code/query. I'm a networking/security guy by trade, just dabbling with this coding malarkey. I've learned the same when folk are new to the trade. Give a few pointers and let them at it.

No doubt I'll be back with some more questions.... probably equally dopey heh!

Please or to participate in this conversation.