diff --git a/app/app/Http/Controllers/TableController.php b/app/app/Http/Controllers/TableController.php index c5e7fc28..fe53a95f 100644 --- a/app/app/Http/Controllers/TableController.php +++ b/app/app/Http/Controllers/TableController.php @@ -11,6 +11,29 @@ class TableController { + public function as(bool $spladeQueryBuilder = false) + { + $query = User::query()->orderBy('name'); + + $resource = $spladeQueryBuilder ? $query : $query->paginate(10); + + $table = SpladeTable::for($resource) + ->column('name') + ->column('email', as: function ($email, $user) { + if ($email === $user->email) { + return strrev($email); + } + }); + + if ($spladeQueryBuilder) { + $table->paginate(10); + } + + return view('table.users', [ + 'users' => $table, + ]); + } + public function custom(bool $spladeQueryBuilder = false) { $query = User::query()->orderBy('name'); diff --git a/app/routes/web.php b/app/routes/web.php index 91736dde..62382e02 100644 --- a/app/routes/web.php +++ b/app/routes/web.php @@ -313,6 +313,7 @@ Route::get('/modal', [TableController::class, 'modal'])->name('table.modal'); + Route::get('/as/{spladeQueryBuilder?}', [TableController::class, 'as'])->name('table.as'); Route::get('/boolean/{spladeQueryBuilder?}', [TableController::class, 'boolean'])->name('table.boolean'); Route::get('/custom/{spladeQueryBuilder?}', [TableController::class, 'custom'])->name('table.custom'); Route::get('/noPerPage/{spladeQueryBuilder?}', [TableController::class, 'noPerPage'])->name('table.noPerPage'); diff --git a/app/tests/Browser/Table/FilterTest.php b/app/tests/Browser/Table/FilterTest.php index 0b63991e..e1130e06 100644 --- a/app/tests/Browser/Table/FilterTest.php +++ b/app/tests/Browser/Table/FilterTest.php @@ -38,6 +38,26 @@ public function it_can_use_select_filters($url) }); } + /** + * @test + * + * @dataProvider booleanDataset + */ + public function it_can_provide_a_callback_to_transform_the_value($spladeQueryBuilder) + { + $this->browse(function (Browser $browser) use ($spladeQueryBuilder) { + User::orderBy('name')->first()->forceFill([ + 'is_admin' => '1', + ])->save(); + + $firstUser = User::query()->orderBy('name')->first(); + + $browser->visit('/table/as/' . (int) $spladeQueryBuilder) + ->assertSeeIn('tr:nth-child(1) td:nth-child(1)', $firstUser->name) + ->assertSeeIn('tr:nth-child(1) td:nth-child(2)', strrev($firstUser->email)); + }); + } + /** * @test * diff --git a/lib/Components/Select.vue b/lib/Components/Select.vue index 0f0ad960..6be027d1 100644 --- a/lib/Components/Select.vue +++ b/lib/Components/Select.vue @@ -166,6 +166,10 @@ export default { return this.initChoices(this.element).then(() => { this.loadRemoteOptions(); }); + } else if(this.stack > 0) { + this.element.addEventListener("change", () => { + this.element.blur(); + }); } this.loadRemoteOptions(); @@ -276,10 +280,9 @@ export default { if(!this.remoteUrl) { return; } - + this.loading = true; - - + Axios({ url: this.remoteUrl, method: "GET", @@ -304,7 +307,8 @@ export default { destroyChoicesInstance() { if(this.choices && this.choicesInstance) { if(this.headlessListener) { - document.querySelector("#headlessui-portal-root")?.removeEventListener("click", this.headlessListener); + document.querySelector("#headlessui-portal-root")?.removeEventListener("click", this.headlessListener, { capture: true }); + this.headlessListener = null; } if(this.selectChangeListener) { @@ -445,10 +449,11 @@ export default { } const isActive = vm.choicesInstance.dropdown.isActive; + const isTargeted = vm.choicesInstance.containerOuter.element.contains(e.target); - if(!isActive && e.target === selectElement) { + if(!isActive && isTargeted) { vm.choicesInstance.showDropdown(); - } else if(isActive && e.target !== selectElement) { + } else if(isActive && !isTargeted) { vm.choicesInstance.hideDropdown(); } }; diff --git a/src/Components/Table.php b/src/Components/Table.php index d940bcf5..827c718e 100644 --- a/src/Components/Table.php +++ b/src/Components/Table.php @@ -122,7 +122,13 @@ public function sortBy(Column $column): string */ public function getColumnDataFromItem($item, Column $column) { - return $column->getDataFromItem($item); + $value = $column->getDataFromItem($item); + + if (is_callable($as = $column->as)) { + return call_user_func($as, $value, $item); + } + + return $value; } /** diff --git a/src/Table/Column.php b/src/Table/Column.php index e2811afd..69dd9eb2 100644 --- a/src/Table/Column.php +++ b/src/Table/Column.php @@ -28,6 +28,7 @@ public function __construct( public Closure|string|null $exportFormat = null, public Closure|array|null $exportStyling = null, public array|string|null $classes = null, + public Closure|null $as = null, ) { if (is_array($classes)) { $classes = Arr::flatten($classes); @@ -53,6 +54,7 @@ public function clone(): static $this->exportFormat, $this->exportStyling, $this->classes, + $this->as, ); } diff --git a/src/Table/HasColumns.php b/src/Table/HasColumns.php index 4144d67e..73328ea8 100644 --- a/src/Table/HasColumns.php +++ b/src/Table/HasColumns.php @@ -55,6 +55,7 @@ public function column( callable|string|null $exportFormat = null, callable|array|null $exportStyling = null, array|string|null $classes = null, + callable|null $as = null, ): self { $key = $key !== null ? $key : Str::kebab($label); $label = $label !== null ? $label : Str::headline(str_replace('.', ' ', $key)); @@ -81,6 +82,7 @@ public function column( exportFormat: $exportFormat, exportStyling: $exportStyling, classes: $classes, + as: $as, ))->values(); if (!$searchable) { diff --git a/src/TableExporter.php b/src/TableExporter.php index 631c14a5..28086cbc 100644 --- a/src/TableExporter.php +++ b/src/TableExporter.php @@ -124,13 +124,17 @@ public function styles(Worksheet $sheet) public function map($item): array { return $this->columns()->map(function (Column $column) use ($item) { - $exportAs = $column->exportAs; - $value = $column->getDataFromItem($item); - return is_callable($exportAs) - ? call_user_func($exportAs, $value, $item, $this->writerType) - : $value; + if (is_callable($exportAs = $column->exportAs)) { + return call_user_func($exportAs, $value, $item, $this->writerType); + } + + if (is_callable($as = $column->as)) { + return call_user_func($as, $value, $item); + } + + return $value; })->all(); }