Skip to content

Commit a48de6f

Browse files
Resolve conflicts
1 parent 4a8b7d3 commit a48de6f

File tree

4 files changed

+123
-98
lines changed

4 files changed

+123
-98
lines changed

resources/dist/tree.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/js/index.js

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,33 @@
11
import Treeselect from 'treeselectjs'
22

3-
export default function tree({
4-
state,
5-
name,
6-
options,
7-
searchable,
8-
showCount,
9-
placeholder,
10-
disabledBranchNode,
11-
disabled = false,
12-
isSingleSelect = true,
13-
showTags = true,
14-
clearable = true,
15-
isIndependentNodes = true,
16-
alwaysOpen = false,
17-
emptyText,
18-
expandSelected = true,
19-
grouped = true,
20-
}) {
3+
export default function tree(
4+
{
5+
state,
6+
name,
7+
options,
8+
searchable,
9+
showCount,
10+
placeholder,
11+
disabledBranchNode = true,
12+
disabled = false,
13+
isSingleSelect = true,
14+
showTags = true,
15+
clearable = true,
16+
isIndependentNodes = true,
17+
alwaysOpen = false,
18+
emptyText,
19+
expandSelected = true,
20+
grouped = true,
21+
}) {
2122
return {
2223
state,
2324
tree: null,
2425
init() {
25-
const values = isSingleSelect
26-
? (this.state !== null ? this.state : '')
27-
: (this.state !== null ? this.state.split(',') : []);
28-
2926
this.tree = new Treeselect({
3027
id: `tree-${name}-id`,
3128
ariaLabel: `tree-${name}-label`,
3229
parentHtmlContainer: this.$refs.tree,
33-
value: values,
30+
value: this.state,
3431
options,
3532
searchable,
3633
showCount,
@@ -48,11 +45,7 @@ export default function tree({
4845
});
4946

5047
this.tree.srcElement.addEventListener('input', (e) => {
51-
if (Array.isArray(e.detail)) {
52-
this.state = e.detail.join(",");
53-
} else {
54-
this.state = e.detail;
55-
}
48+
this.state = e.detail;
5649
});
5750
}
5851
}

resources/views/select-tree.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
searchable: '{{ $isSearchable() }}',
1919
showCount: '{{ $getWithCount() }}',
2020
placeholder: '{{ $getPlaceholder() }}',
21-
disabledBranchNode: '{{ $getDisabledBranchNode() }}',
21+
disabledBranchNode: '{{ !$getEnableBranchNode() }}',
2222
disabled: '{{ $isDisabled() }}',
2323
isSingleSelect: '{{ !$getMultiple() }}',
2424
isIndependentNodes: '{{ $getIndependent() }}',

src/SelectTree.php

Lines changed: 100 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@
77
use Filament\Forms\Components\Concerns\CanBeSearchable;
88
use Filament\Forms\Components\Concerns\HasPlaceholder;
99
use Filament\Forms\Components\Field;
10+
use Illuminate\Database\Eloquent\Concerns\HasRelationships;
11+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
12+
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
1013
use Illuminate\Support\Collection;
1114

1215
class SelectTree extends Field
1316
{
17+
use HasRelationships;
1418
use CanBeDisabled;
1519
use CanBeSearchable;
1620
use HasPlaceholder;
@@ -27,21 +31,19 @@ class SelectTree extends Field
2731

2832
protected bool $independent = true;
2933

34+
protected string $titleAttribute;
35+
3036
protected bool $clearable = true;
3137

3238
protected bool $expandSelected = true;
3339

34-
protected bool $disabledBranchNode = false;
40+
protected bool $enableBranchNode = false;
3541

3642
protected bool $grouped = true;
3743

38-
protected ?string $treeModel = null;
39-
4044
protected array $options = [];
4145

42-
protected string $treeParentKey;
43-
44-
protected string $titleAttribute;
46+
protected string|Closure $relationship;
4547

4648
protected ?Closure $modifyQueryUsing;
4749

@@ -52,6 +54,92 @@ public function withCount(bool $withCount = true): static
5254
return $this;
5355
}
5456

57+
protected function setUp(): void
58+
{
59+
$this->relationship = $this->getName();
60+
61+
$this->loadStateFromRelationshipsUsing(static function (self $component): void {
62+
$relationship = $component->getRelationship();
63+
if ($relationship instanceof BelongsTo) {
64+
$component->state($relationship->getResults()?->getKey());
65+
} else {
66+
$results = $relationship->getResults();
67+
$state = $results
68+
->pluck($relationship->getRelatedKeyName())
69+
->toArray();
70+
$component->state($state);
71+
}
72+
});
73+
74+
$this->saveRelationshipsUsing(static function (self $component, $state) {
75+
if ($component->getRelationship() instanceof BelongsToMany) {
76+
$state = Collection::wrap($state ?? []);
77+
$component->getRelationship()->sync($state->toArray());
78+
$component->dehydrated(false);
79+
}
80+
});
81+
82+
}
83+
84+
private function buildTree(int $parent = null): array|Collection
85+
{
86+
87+
if ($this->getOptions()) {
88+
return $this->getOptions();
89+
}
90+
91+
if ($this->getRelationship() instanceof BelongsTo) {
92+
$key = $this->getRelationship()->getForeignKeyName();
93+
}
94+
95+
if ($this->getRelationship() instanceof BelongsToMany) {
96+
$key = $this->getRelationship()->getRelatedPivotKeyName();
97+
}
98+
99+
$defaultQuery = $this->getRelationship()->getRelated()->query()
100+
->where($key, $parent);
101+
102+
// // If we're not at the root level and a modification callback is provided, apply it.
103+
// if (!$parent && $this->modifyQueryUsing) {
104+
// $defaultQuery = $this->evaluate($this->modifyQueryUsing, ['query' => $defaultQuery]);
105+
// }
106+
107+
// Fetch the results from the default query.
108+
$results = $defaultQuery->get();
109+
110+
// Map the results into a tree structure.
111+
return $results->map(function ($result) {
112+
113+
// Recursively build children trees for the current result.
114+
$children = $this->buildTree($result->id);
115+
116+
// Create an array representation of the current result with children.
117+
return [
118+
'name' => $result->name,
119+
'value' => $result->id,
120+
'children' => $children->isEmpty() ? null : $children->toArray(),
121+
];
122+
});
123+
}
124+
125+
public function relationship(string $relationship, string $titleAttribute): self
126+
{
127+
$this->relationship = $relationship;
128+
$this->titleAttribute = $titleAttribute;
129+
130+
return $this;
131+
}
132+
133+
public function getRelationship(): BelongsToMany|BelongsTo
134+
{
135+
return $this->getModelInstance()->{$this->evaluate($this->relationship)}();
136+
}
137+
138+
public function getTitleAttribute(): string
139+
{
140+
return $this->evaluate($this->titleAttribute);
141+
}
142+
55143
public function clearable(bool $clearable = true): static
56144
{
57145
$this->clearable = $clearable;
@@ -94,23 +182,16 @@ public function alwaysOpen(bool $alwaysOpen = true): static
94182
return $this;
95183
}
96184

97-
public function multiple(bool $multiple = true): static
98-
{
99-
$this->multiple = $multiple;
100-
101-
return $this;
102-
}
103-
104185
public function options(array $options): static
105186
{
106187
$this->options = $options;
107188

108189
return $this;
109190
}
110191

111-
public function disabledBranchNode(bool $disabledBranchNode = true): static
192+
public function enableBranchNode(bool $enableBranchNode = true): static
112193
{
113-
$this->disabledBranchNode = $disabledBranchNode;
194+
$this->enableBranchNode = $enableBranchNode;
114195

115196
return $this;
116197
}
@@ -142,7 +223,7 @@ public function getWithCount(): bool
142223

143224
public function getMultiple(): bool
144225
{
145-
return $this->evaluate($this->multiple);
226+
return $this->evaluate($this->getRelationship() instanceof BelongsToMany);
146227
}
147228

148229
public function getClearable(): bool
@@ -160,62 +241,13 @@ public function getOptions(): array
160241
return $this->evaluate($this->options);
161242
}
162243

163-
public function getDisabledBranchNode(): bool
244+
public function getEnableBranchNode(): bool
164245
{
165-
return $this->evaluate($this->disabledBranchNode);
246+
return $this->evaluate($this->enableBranchNode);
166247
}
167248

168249
public function getEmptyLabel(): string
169250
{
170-
return ! $this->emptyLabel ? __('No results found') : $this->evaluate($this->emptyLabel);
171-
}
172-
173-
public function tree(string $treeModel, string $treeParentKey, string $titleAttribute, Closure $modifyQueryUsing = null): static
174-
{
175-
$this->treeModel = $treeModel;
176-
$this->treeParentKey = $treeParentKey;
177-
$this->titleAttribute = $titleAttribute;
178-
$this->modifyQueryUsing = $modifyQueryUsing;
179-
180-
return $this;
181-
}
182-
183-
private function buildTree(int $parent = null): array|Collection
184-
{
185-
// Check if custom options are set; if yes, return them.
186-
if ($this->getOptions()) {
187-
return $this->getOptions();
188-
}
189-
190-
// Check if the treeModel is not set; if yes, return an empty collection.
191-
if (! $this->treeModel) {
192-
return collect();
193-
}
194-
195-
// Create a default query to fetch items with the specified parent ID.
196-
$defaultQuery = $this->treeModel::query()
197-
->where($this->treeParentKey, $parent);
198-
199-
// If we're not at the root level and a modification callback is provided, apply it.
200-
if (! $parent && $this->modifyQueryUsing) {
201-
$defaultQuery = $this->evaluate($this->modifyQueryUsing, ['query' => $defaultQuery]);
202-
}
203-
204-
// Fetch the results from the default query.
205-
$results = $defaultQuery->get();
206-
207-
// Map the results into a tree structure.
208-
return $results->map(function ($result) {
209-
210-
// Recursively build children trees for the current result.
211-
$children = $this->buildTree($result->id);
212-
213-
// Create an array representation of the current result with children.
214-
return [
215-
'name' => $result->{$this->titleAttribute},
216-
'value' => $this->getMultiple() ? $result->{$this->titleAttribute} : $result->id,
217-
'children' => $children->isEmpty() ? null : $children->toArray(),
218-
];
219-
});
251+
return $this->emptyLabel ? $this->evaluate($this->emptyLabel) : __('No results found');
220252
}
221253
}

0 commit comments

Comments
 (0)