MedicOneSystems / livewire-datatables

Advanced datatables using Laravel, Livewire, Tailwind CSS and Alpine JS
https://livewire-datatables.com/
MIT License
1.19k stars 258 forks source link

Unable to dynamically build colums #520

Closed rgoodmanfirefly closed 1 year ago

rgoodmanfirefly commented 1 year ago

To keep this as short as possible, this issue arose from a feature I'm trying to build where the user can select from a list of options and have data returned to them in the form of a table. I was in need of greater filtering abilities than my standard HTML table, and Livewire Datatables seemed the perfect option.

However, I have not been able to find a way to build Livewire Datatable columns based on user input in a way that it is happy with. I will share my closest solution that I would like to see a fix for:

The following obviously works. It creates a simple two column table.

public function columns() {
    $cols = [
        DateColumn::name('date')
            ->label('Date')
            ->filterable()
            ->hideable(),
        Column::name('devices.name')
            ->label('Device')
            ->filterable()
            ->hideable(),
    ];

    return $cols;
}

The following does not work... at least, not entirely. I store data (theoretically created from user input) as a plain array and loop through to build the column objects.

public function columns()
{
    $colsRaw = [
        [
            'column' => 'Mediconesystems\\LivewireDatatables\\DateColumn',
            'name' => 'date',
            'label' => 'Date',
            'filterable' => true,
            'hideable' => true,
        ],
        [
            'column' => 'Mediconesystems\\LivewireDatatables\\Column',
            'name' => 'devices.name',
            'label' => 'Devices',
            'filterable' => true,
            'hideable' => true,
        ],
    ];

    foreach($colsRaw as $key => $val) {
        $instance = app()->make($val['column']);
        $columnName = $val['name'];
        $item = $instance->name($columnName);
        $item->filterable = true;
        $item->hideable = true;

        array_push($this->cols, $item);
    }

    return $this->cols;
}

dding both $cols and $this->cols from the above examples returns the exact same thing. Both examples build a table properly. The problem is, with the second example, the instant I try to interact with the table in any way (using filters, using pagination), I get the following error:

Firefly Dashboard (9)

This has left me scratching my head for the last week, and I can't seem to come to any conclusion other than that it's a bug of some sort. There doesn't seem to be any reason why Livewire would be unhappy with this method of class instantiation, not that I can think of. I've posted on Laracasts and Stackoverflow about this a total of 3 times with no luck, so I'm hoping I will finally find some answers over here. Thank you!

renardudezert commented 1 year ago

Hi, It's because (i think) your $cols variable is public in your class. By setting the variable public, livewire interacts with it when a request is sent. That's why you get this error. In order to avoid it, the best solution is to set a $datatable_cols variable (for example) as private, and update it during the specific livewire lifecycle hook is called (updated, when you set the cols with the user input).
Use this var ONLY for the columns() property

rgoodmanfirefly commented 1 year ago

@renardudezert This solved my issue, I can't believe it was so simple. Thank you!