Skip to content

Commit f90e2c1

Browse files
Merge pull request #147 from lotestudio/multiple-prepend-feature
Add `multiple` and `prepend` features
2 parents 73c72a8 + 5fa9f97 commit f90e2c1

File tree

2 files changed

+96
-27
lines changed

2 files changed

+96
-27
lines changed

README.md

+72-24
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
[![Latest Version on Packagist](https://img.shields.io/packagist/v/codewithdennis/filament-select-tree.svg?style=flat-square)](https://packagist.org/packages/codewithdennis/filament-select-tree)
44
[![Total Downloads](https://img.shields.io/packagist/dt/codewithdennis/filament-select-tree.svg?style=flat-square)](https://packagist.org/packages/codewithdennis/filament-select-tree)
55

6-
This package adds a dynamic select tree field to your Laravel / Filament application, allowing you to create interactive hierarchical selection dropdowns based on relationships. It's handy for building selection dropdowns with various customization options.
6+
This package adds a dynamic select tree field to your Laravel / Filament application, allowing you to create interactive hierarchical selection dropdowns based on relationships. It's handy for
7+
building selection dropdowns with various customization options.
78

89
![thumbnail](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/thumbnail.jpg)
910

@@ -23,14 +24,14 @@ php artisan filament:assets
2324

2425
Use the tree for a `BelongsToMany` relationship
2526

26-
```PHP
27+
```php
2728
SelectTree::make('categories')
2829
->relationship('categories', 'name', 'parent_id')
2930
```
3031

3132
Use the tree for a `BelongsTo` relationship
3233

33-
```PHP
34+
```php
3435
SelectTree::make('category_id')
3536
->relationship('category', 'name', 'parent_id')
3637
```
@@ -39,14 +40,14 @@ SelectTree::make('category_id')
3940

4041
Customize the parent query
4142

42-
```PHP
43+
```php
4344
SelectTree::make('categories')
4445
->relationship(relationship: 'categories', titleAttribute: 'name', parentAttribute: 'parent_id', modifyQueryUsing: fn($query) => $query));
4546
```
4647

4748
Customize the child query
4849

49-
```PHP
50+
```php
5051
SelectTree::make('categories')
5152
->relationship(relationship: 'categories', titleAttribute: 'name', parentAttribute: 'parent_id', modifyChildQueryUsing: fn($query) => $query));
5253
```
@@ -55,121 +56,167 @@ SelectTree::make('categories')
5556

5657
Set a custom placeholder when no items are selected
5758

58-
```PHP
59+
```php
5960
->placeholder(__('Please select a category'))
6061
```
6162

6263
Enable the selection of groups
6364

64-
```PHP
65+
```php
6566
->enableBranchNode()
6667
```
6768

6869
Customize the label when there are zero search results
6970

70-
```PHP
71+
```php
7172
->emptyLabel(__('Oops, no results have been found!'))
7273
```
7374

7475
Display the count of children alongside the group's name
7576

76-
```PHP
77+
```php
7778
->withCount()
7879
```
7980

8081
Keep the dropdown open at all times
8182

82-
```PHP
83+
```php
8384
->alwaysOpen()
8485
```
8586

8687
Set nodes as dependent
8788

88-
```PHP
89+
```php
8990
->independent(false)
9091
```
9192

9293
Expand the tree with selected values (only works if field is dependent)
9394

94-
```PHP
95+
```php
9596
->expandSelected(false)
9697
```
9798

9899
Set the parent's null value to -1, allowing you to use -1 as a sentinel value (default = null)
99100

100-
```PHP
101+
```php
101102
->parentNullValue(-1)
102103
```
103104

104105
All groups will be opened to this level
105106

106-
```PHP
107+
```php
107108
->defaultOpenLevel(2)
108109
```
109110

110111
Specify the list's force direction. Options include: auto (default), top, and bottom.
111112

112-
```PHP
113+
```php
113114
->direction('top')
114115
```
115116

116117
Display individual leaf nodes instead of the main group when all leaf nodes are selected
117118

118-
```PHP
119+
```php
119120
->grouped(false)
120121
```
121122

122123
Hide the clearable icon
123124

124-
```PHP
125+
```php
125126
->clearable(false)
126127
```
127128

128129
Activate the search functionality
129130

130-
```PHP
131+
```php
131132
->searchable();
132133
```
133134

134135
Disable specific options in the tree
135136

136-
```PHP
137+
```php
137138
->disabledOptions([2, 3, 4])
138139
```
139140

140141
Hide specific options in the tree
141142

142-
```PHP
143+
```php
143144
->hiddenOptions([2, 3, 4])
144145
```
145146

146147
Allow soft deleted items to be displayed
147148

148-
```PHP
149+
```php
149150
->withTrashed()
150151
```
151152

152153
Specify a different key for your model.
153154
For example: you have id, code and parent_code. Your model uses id as key, but the parent-child relation is established between code and parent_code
154155

155-
```PHP
156+
```php
156157
->withKey('code')
157158
```
158159

159160
Store fetched models for additional functionality
160161

161-
```PHP
162+
```php
162163
->storeResults()
163164
```
164165

165166
Now you can access the results in `disabledOptions` or `hiddenOptions`
166167

167-
```PHP
168+
```php
168169
->disabledOptions(function ($state, SelectTree $component) {
169170
$results = $component->getResults();
170171
})
171172
```
172173

174+
By default, the type of selection in the tree (single or multiple) is determined by the relationship type: `BelongsTo` for single selection and `BelongsToMany` for multiple selection. If you want to
175+
explicitly set the selection type, use:
176+
177+
```php
178+
->multiple(false)
179+
```
180+
181+
If you need to prepend an item to the tree menu, use the `prepend` method. This method accepts an array or a closure. It is useful when the tree-select is used as a filter (see example below).
182+
183+
```php
184+
use Filament\Tables\Filters\Filter;
185+
use Illuminate\Database\Eloquent\Builder;
186+
use CodeWithDennis\FilamentSelectTree\SelectTree;
187+
```
188+
189+
```php
190+
->filters([
191+
Filter::make('tree')
192+
->form([
193+
SelectTree::make('category')
194+
->relationship('categories', 'name', 'parent_id')
195+
->enableBranchNode()
196+
->multiple(false)
197+
->prepend([
198+
'name' => 'Uncategorized Records',
199+
'value' => -1,
200+
'parent' => null, // optional
201+
'disabled' => false, // optional
202+
'hidden' => false, // optional
203+
'children' => [], // optional
204+
])
205+
])
206+
->query(function (Builder $query, array $data) {
207+
$categories = [(int) $data['category']];
208+
209+
return $query->when($data['category'], function (Builder $query, $categories) {
210+
if($data['category'] === -1){
211+
return $query->whereDoesntHave('categories');
212+
}
213+
214+
return $query->whereHas('categories', fn(Builder $query) => $query->whereIn('id', $categories));
215+
});
216+
})
217+
])
218+
```
219+
173220
## Filters
174221

175222
Use the tree in your table filters. Here's an example to show you how.
@@ -205,6 +252,7 @@ use CodeWithDennis\FilamentSelectTree\SelectTree;
205252
```
206253

207254
## Screenshots
255+
208256
![example-1](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/example-1.jpg)
209257
![example-2](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/example-2.jpg)
210258
![example-3](https://raw.githubusercontent.com/CodeWithDennis/filament-select-tree/3.x/resources/images/example-3.jpg)

src/SelectTree.php

+24-3
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ class SelectTree extends Field implements HasAffixActions
8484

8585
protected Collection|array|null $results = null;
8686

87+
protected Closure|bool|null $multiple = null;
88+
89+
protected Closure|array|null $prepend = null;
90+
8791
protected function setUp(): void
8892
{
8993
// Load the state from relationships using a callback function.
@@ -143,7 +147,7 @@ protected function setUp(): void
143147
]);
144148
}
145149

146-
private function buildTree(): Collection
150+
protected function buildTree(): Collection
147151
{
148152
// Start with two separate query builders
149153
$nullParentQuery = $this->getRelationship()->getRelated()->query()->where($this->getParentAttribute(), $this->getParentNullValue());
@@ -288,6 +292,20 @@ public function parentNullValue(int|string|null $parentNullValue = null): static
288292
return $this;
289293
}
290294

295+
public function multiple(Closure|bool $multiple = true): static
296+
{
297+
$this->multiple = $multiple;
298+
299+
return $this;
300+
}
301+
302+
public function prepend(Closure|array|null $prepend = null): static
303+
{
304+
$this->prepend = $prepend;
305+
306+
return $this;
307+
}
308+
291309
public function getRelationship(): BelongsToMany|BelongsTo
292310
{
293311
return $this->getModelInstance()->{$this->evaluate($this->relationship)}();
@@ -394,7 +412,8 @@ public function storeResults(bool $storeResults = true): static
394412

395413
public function getTree(): Collection|array
396414
{
397-
return $this->evaluate($this->buildTree());
415+
return $this->evaluate($this->buildTree()->when($this->prepend,
416+
fn (Collection $tree) => $tree->prepend($this->evaluate($this->prepend))));
398417
}
399418

400419
public function getResults(): Collection|array|null
@@ -434,7 +453,9 @@ public function getWithCount(): bool
434453

435454
public function getMultiple(): bool
436455
{
437-
return $this->evaluate($this->getRelationship() instanceof BelongsToMany);
456+
return $this->evaluate(
457+
is_null($this->multiple) ? $this->getRelationship() instanceof BelongsToMany : $this->evaluate($this->multiple)
458+
);
438459
}
439460

440461
public function getClearable(): bool

0 commit comments

Comments
 (0)