Skip to content

Commit 7022f52

Browse files
committed
Adding MultiSelectDropdownFilter
1 parent 7281989 commit 7022f52

File tree

8 files changed

+252
-6
lines changed

8 files changed

+252
-6
lines changed

docs/filters/creating-filters.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,29 @@ public function filters(): array
8989
}
9090
```
9191

92+
## Multi-select dropdown Filters
93+
94+
Multi-select dropdown filters are a simple dropdown list. The user can select multiple options from the list. There is also an 'All' option that will select all values.
95+
96+
```php
97+
use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectDropdownFilter;
98+
99+
public function filters(): array
100+
{
101+
return [
102+
MultiSelectDropdownFilter::make('Tags')
103+
->options(
104+
Tag::query()
105+
->orderBy('name')
106+
->get()
107+
->keyBy('id')
108+
->map(fn($tag) => $tag->name)
109+
->toArray()
110+
),
111+
];
112+
}
113+
```
114+
92115
## Date Filters
93116

94117
Date filters are HTML date elements.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
@php
2+
$theme = $component->getTheme();
3+
@endphp
4+
5+
@if ($theme === 'tailwind')
6+
<div class="rounded-md shadow-sm">
7+
<select multiple
8+
wire:model.stop="{{ $component->getTableName() }}.filters.{{ $filter->getKey() }}"
9+
wire:key="{{ $component->getTableName() }}-filter-{{ $filter->getKey() }}"
10+
id="{{ $component->getTableName() }}-filter-{{ $filter->getKey() }}"
11+
class="block w-full transition duration-150 ease-in-out border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 dark:bg-gray-800 dark:text-white dark:border-gray-600"
12+
>
13+
@foreach($filter->getOptions() as $key => $value)
14+
@if (is_iterable($value))
15+
<optgroup label="{{ $key }}">
16+
@foreach ($value as $optionKey => $optionValue)
17+
<option value="{{ $optionKey }}">{{ $optionValue }}</option>
18+
@endforeach
19+
</optgroup>
20+
@else
21+
<option value="{{ $key }}">{{ $value }}</option>
22+
@endif
23+
@endforeach
24+
</select>
25+
</div>
26+
@elseif ($theme === 'bootstrap-4' || $theme === 'bootstrap-5')
27+
<select multiple
28+
wire:model.stop="{{ $component->getTableName() }}.filters.{{ $filter->getKey() }}"
29+
wire:key="{{ $component->getTableName() }}-filter-{{ $filter->getKey() }}"
30+
id="{{ $component->getTableName() }}-filter-{{ $filter->getKey() }}"
31+
class="{{ $theme === 'bootstrap-4' ? 'form-control' : 'form-select' }}"
32+
>
33+
@foreach($filter->getOptions() as $key => $value)
34+
@if (is_iterable($value))
35+
<optgroup label="{{ $key }}">
36+
@foreach ($value as $optionKey => $optionValue)
37+
<option value="{{ $optionKey }}">{{ $optionValue }}</option>
38+
@endforeach
39+
</optgroup>
40+
@else
41+
<option value="{{ $key }}">{{ $value }}</option>
42+
@endif
43+
@endforeach
44+
</select>
45+
@endif

src/Traits/Helpers/FilterHelpers.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Illuminate\Support\Collection;
66
use Rappasoft\LaravelLivewireTables\Views\Filter;
77
use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectFilter;
8+
use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectDropdownFilter;
89

910
trait FilterHelpers
1011
{
@@ -91,7 +92,7 @@ public function selectAllFilterOptions(string $filterKey): void
9192
{
9293
$filter = $this->getFilterByKey($filterKey);
9394

94-
if (! $filter instanceof MultiSelectFilter) {
95+
if (! $filter instanceof MultiSelectFilter && ! $filter instanceof MultiSelectDropdownFilter) {
9596
return;
9697
}
9798

@@ -175,7 +176,7 @@ public function resetFilter($filter): void
175176
if (! $filter instanceof Filter) {
176177
$filter = $this->getFilterByKey($filter);
177178
}
178-
179+
179180
$this->setFilter($filter->getKey(), $filter->getDefaultValue());
180181
}
181182

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
namespace Rappasoft\LaravelLivewireTables\Views\Filters;
4+
5+
use Rappasoft\LaravelLivewireTables\DataTableComponent;
6+
use Rappasoft\LaravelLivewireTables\Views\Filter;
7+
8+
class MultiSelectDropdownFilter extends Filter
9+
{
10+
protected array $options = [];
11+
12+
public function options(array $options = []): MultiSelectDropdownFilter
13+
{
14+
$this->options = $options;
15+
16+
return $this;
17+
}
18+
19+
public function getOptions(): array
20+
{
21+
return $this->options;
22+
}
23+
24+
public function getKeys(): array
25+
{
26+
return collect($this->getOptions())
27+
->keys()
28+
->map(fn ($value) => (string)$value)
29+
->filter(fn ($value) => strlen($value))
30+
->values()
31+
->toArray();
32+
}
33+
34+
public function validate($value)
35+
{
36+
if (is_array($value)) {
37+
foreach ($value as $index => $val) {
38+
// Remove the bad value
39+
if (! in_array($val, $this->getKeys())) {
40+
unset($value[$index]);
41+
}
42+
}
43+
}
44+
45+
return $value;
46+
}
47+
48+
public function getDefaultValue()
49+
{
50+
return [];
51+
}
52+
53+
public function getFilterPillValue($value): ?string
54+
{
55+
$values = [];
56+
57+
foreach ($value as $item) {
58+
$found = $this->getCustomFilterPillValue($item) ?? $this->getOptions()[$item] ?? null;
59+
60+
if ($found) {
61+
$values[] = $found;
62+
}
63+
}
64+
65+
return implode(', ', $values);
66+
}
67+
68+
public function isEmpty($value): bool
69+
{
70+
return ! is_array($value);
71+
}
72+
73+
public function render(DataTableComponent $component)
74+
{
75+
return view('livewire-tables::components.tools.filters.multi-select-dropdown', [
76+
'component' => $component,
77+
'filter' => $this,
78+
]);
79+
}
80+
}

tests/Http/Livewire/PetsTable.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
use Rappasoft\LaravelLivewireTables\DataTableComponent;
77
use Rappasoft\LaravelLivewireTables\Tests\Models\Breed;
88
use Rappasoft\LaravelLivewireTables\Tests\Models\Pet;
9+
use Rappasoft\LaravelLivewireTables\Tests\Models\Species;
910
use Rappasoft\LaravelLivewireTables\Views\Column;
1011
use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectFilter;
12+
use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectDropdownFilter;
1113

1214
class PetsTable extends DataTableComponent
1315
{
@@ -56,6 +58,18 @@ public function filters(): array
5658
->filter(function (Builder $builder, array $values) {
5759
return $builder->whereIn('breed_id', $values);
5860
}),
61+
MultiSelectDropdownFilter::make('Species')
62+
->options(
63+
Species::query()
64+
->orderBy('name')
65+
->get()
66+
->keyBy('id')
67+
->map(fn ($species) => $species->name)
68+
->toArray()
69+
)
70+
->filter(function (Builder $builder, array $values) {
71+
return $builder->whereIn('species_id', $values);
72+
}),
5973
];
6074
}
6175
}

tests/Traits/Configuration/FilterConfigurationTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,27 @@ public function filters_layout_can_be_set(): void
100100

101101
$this->basicTable->setFilterLayout('popover');
102102
}
103+
104+
/** @test */
105+
/* Not present in this branch
106+
public function filters_layout_popover_default_can_be_set(): void
107+
{
108+
$this->assertFalse($this->basicTable->filterSlideDownDefaultVisible);
109+
110+
$this->basicTable->setFilterSlideDownDefaultStatusEnabled();
111+
112+
$this->assertTrue($this->basicTable->filterSlideDownDefaultVisible);
113+
114+
$this->basicTable->setFilterSlideDownDefaultStatusDisabled();
115+
116+
$this->assertFalse($this->basicTable->filterSlideDownDefaultVisible);
117+
118+
$this->basicTable->setFilterSlideDownDefaultStatus(true);
119+
120+
$this->assertTrue($this->basicTable->filterSlideDownDefaultVisible);
121+
122+
$this->basicTable->setFilterSlideDownDefaultStatus(false);
123+
124+
$this->assertFalse($this->basicTable->filterSlideDownDefaultVisible);
125+
}*/
103126
}

tests/Traits/Helpers/FilterHelpersTest.php

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Rappasoft\LaravelLivewireTables\Tests\TestCase;
66
use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectFilter;
7+
use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectDropdownFilter;
78

89
class FilterHelpersTest extends TestCase
910
{
@@ -59,12 +60,14 @@ public function can_check_if_component_has_filters(): void
5960
public function can_get_component_filters(): void
6061
{
6162
$this->assertInstanceOf(MultiSelectFilter::class, $this->basicTable->getFilters()[0]);
63+
$this->assertInstanceOf(MultiSelectDropdownFilter::class, $this->basicTable->getFilters()[1]);
64+
6265
}
6366

6467
/** @test */
6568
public function can_get_component_filter_count(): void
6669
{
67-
$this->assertEquals(1, $this->basicTable->getFiltersCount());
70+
$this->assertEquals(2, $this->basicTable->getFiltersCount());
6871
}
6972

7073
/** @test */
@@ -73,6 +76,11 @@ public function can_get_component_filter_by_key(): void
7376
$this->assertNotInstanceOf(MultiSelectFilter::class, $this->basicTable->getFilterByKey('test'));
7477

7578
$this->assertInstanceOf(MultiSelectFilter::class, $this->basicTable->getFilterByKey('breed'));
79+
80+
$this->assertNotInstanceOf(MultiSelectDropdownFilter::class, $this->basicTable->getFilterByKey('test'));
81+
82+
$this->assertInstanceOf(MultiSelectDropdownFilter::class, $this->basicTable->getFilterByKey('species'));
83+
7684
}
7785

7886
/** @test */
@@ -81,6 +89,13 @@ public function can_set_filter_value(): void
8189
$this->basicTable->setFilter('breed', ['1']);
8290

8391
$this->assertSame(['1'], $this->basicTable->getAppliedFilterWithValue('breed'));
92+
93+
$this->basicTable->setFilter('breed', ['0']);
94+
95+
$this->basicTable->setFilter('species', ['1']);
96+
97+
$this->assertSame(['1'], $this->basicTable->getAppliedFilterWithValue('species'));
98+
8499
}
85100

86101
/** @test */
@@ -100,6 +115,8 @@ public function can_select_all_filter_options(): void
100115
3,
101116
102,
102117
], $this->basicTable->getAppliedFilterWithValue('breed'));
118+
119+
103120
}
104121

105122
/** @test */
@@ -111,7 +128,7 @@ public function can_set_filter_defaults(): void
111128

112129
$this->basicTable->setFilterDefaults();
113130

114-
$this->assertSame(['breed' => []], $this->basicTable->getAppliedFilters());
131+
$this->assertSame(['breed' => [], 'species' => []], $this->basicTable->getAppliedFilters());
115132
}
116133

117134
/** @test */
@@ -132,14 +149,25 @@ public function can_see_if_filters_set_with_values(): void
132149
$this->basicTable->setFilter('breed', ['1']);
133150

134151
$this->assertTrue($this->basicTable->hasAppliedFiltersWithValues());
152+
153+
$this->basicTable->setFilter('breed', []);
154+
155+
$this->assertFalse($this->basicTable->hasAppliedFiltersWithValues());
156+
157+
$this->basicTable->setFilter('species', ['1']);
158+
159+
$this->assertTrue($this->basicTable->hasAppliedFiltersWithValues());
160+
135161
}
136162

137163
/** @test */
138164
public function can_get_all_applied_filters_with_values(): void
139165
{
140166
$this->basicTable->setFilter('breed', ['1']);
141167

142-
$this->assertSame(['breed' => ['1']], $this->basicTable->getAppliedFiltersWithValues());
168+
$this->basicTable->setFilter('species', ['0']);
169+
170+
$this->assertSame(['breed' => ['1'], 'species' => ['0']], $this->basicTable->getAppliedFiltersWithValues());
143171
}
144172

145173
/** @test */
@@ -150,6 +178,11 @@ public function can_get_all_applied_filters_with_values_count(): void
150178
$this->basicTable->setFilter('breed', ['1']);
151179

152180
$this->assertSame(1, $this->basicTable->getAppliedFiltersWithValuesCount());
181+
182+
$this->basicTable->setFilter('species', ['1']);
183+
184+
$this->assertSame(2, $this->basicTable->getAppliedFiltersWithValuesCount());
185+
153186
}
154187

155188
/** @test */
@@ -167,4 +200,26 @@ public function can_check_if_filter_layout_is_slidedown(): void
167200

168201
$this->assertTrue($this->basicTable->isFilterLayoutSlideDown());
169202
}
203+
204+
/** @test */
205+
/*
206+
public function can_check_if_filter_layout_slidedown_is_visible(): void
207+
{
208+
$this->assertFalse($this->basicTable->getFilterSlideDownDefaultStatus());
209+
210+
$this->basicTable->setFilterSlideDownDefaultStatusEnabled();
211+
212+
$this->assertTrue($this->basicTable->getFilterSlideDownDefaultStatus());
213+
}*/
214+
215+
/** @test */
216+
/*
217+
public function can_check_if_filter_layout_slidedown_is_hidden(): void
218+
{
219+
$this->assertFalse($this->basicTable->getFilterSlideDownDefaultStatus());
220+
221+
$this->basicTable->setFilterSlideDownDefaultStatusDisabled();
222+
223+
$this->assertFalse($this->basicTable->getFilterSlideDownDefaultStatus());
224+
}*/
170225
}

0 commit comments

Comments
 (0)