coryrose1 / livewire-tables

An extension for Laravel Livewire that allows you to effortlessly scaffold datatables with optional pagination, search, and sort.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Suggestions/recommendations

kdion4891 opened this issue · comments

Here are some suggestions/recommendations.

1. Use a baseQuery instead

Right now you specify a model method, but it makes more sense to use a base query. This would eliminate the need for the with method as well.

For example, instead of this:

public function model()
{
    return User::class;
}

public function with()
{
    return ['address', 'post'];
}

Have something like this:

public function baseQuery()
{
    return User::with(['address', 'post'])->withCount('posts');
}

Notice how I've added withCount to this. Doing it this way makes withCount possible without having to implement a bunch of other methods. Then we would be able to use posts_count in the $fields name.

2. Make field declaration expressive

Right now, you dump the fields into an array. Sure, this works, but it is confusing and makes future updates a nightmare. I propose you do field declaration similar to Laravel Nova. Then developers know exactly what they can do with fields, and makes it nicer to work with.

For example, instead of this:

public $fields = [
    [
        'title' => 'ID',
        'name' => 'id',
        'header_class' => '',
        'cell_class' => '',
        'sortable' => true,
    ],
    [
        'title' => 'City',
        'name' => 'address.city',
        'header_class' => 'bolded',
        'cell_class' => 'bolded bg-green',
        'sortable' => true,
        'searchable' => true,
    ],
];

Have something like this:

public function fields()
{
    return [
        Field::make('ID', 'id')->sortable();
        Field::make('City', 'address.city')->headerClass('bolded')->cellClass('bolded bg-green')->sortable()->searchable();
        Field::make('Posts Count', 'posts_count')->cellClass('text-muted');
    ];
}

Things like searchable/sortable can default to false, and using this method would convert said values to true.

3. Use a single view for all tables

You can use a single view for ALL tables. This would eliminate the need for devs to scaffold their own view files, which is tedious. Since the package dynamically declares stuff anyways, there shouldn't be a need for this. The package can simply publish 1 view file to the views/vendor folder, and the stub used by livewire-tables:make can contain this view by default. Then developers can easily make changes to that one view file if they want, and it would apply to all tables.

In this view, just use @foreach loops to iterate the fields and output the headings, etc..

For example:

@if($hasSearch)
    {{-- show search input etc. --}}
@endif

<table class="table-wrapper">
    <thead>
    <tr>
        @foreach($fields as $field)
            <th class="header {{ $field['headerClass'] }}" wire:click="$emit('sortColumn', {{ $loop->index() }})">{{ $field['title'] }}</th>
        @endforeach
    </tr>
    </thead>
    <tbody>
    @foreach ($rowData as $row)
        <tr>
            @foreach($fields as $field)
                <td class="table-cell {{ $field['cellClass'] }}">
                    @if($field['view'])
                        {{-- field uses a custom view file for the TD :) --}}
                        @include($field['view'])
                    @elseif(strpos($field['name'], '.') !== false)
                        {{-- explode by period or w/e for relationship logic --}}
                        ...
                    @else
                        {{ $row->{$field['name']} }}
                    @endif
                </td>
            @endforeach
        </tr>
    @endforeach
    </tbody>
</table>

@if($paginate)
    {{ $rowData->links() }}
@endif

Notice how I've included a conditional for each TD. If we added a new view() method to the field delcaration, devs could use their own custom view file for the TD, and it would automatically be passed the $row var.

For relationships, we can just check if the name has a period. If it does, explode it into the actual value or w/e. See this: https://stackoverflow.com/questions/33645301/how-do-i-traverse-through-model-relationships-in-laravel-with-dot-syntax

Anyways, these are just a few ideas. Would love to hear your thoughts on these.