Skip to content
This repository was archived by the owner on Mar 18, 2025. It is now read-only.

Commit 8e55e95

Browse files
committed
Fix button display errors when passing values in manually to custom-select - #34
1 parent a123dbd commit 8e55e95

File tree

6 files changed

+42
-27
lines changed

6 files changed

+42
-27
lines changed

dist/form-components.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.

dist/mix-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"/form-components.js": "/form-components.js?id=8a17570b1e33ac3125b9"
2+
"/form-components.js": "/form-components.js?id=2509d89034e6f7c041d5"
33
}

resources/js/components/custom-select.js

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { isArray } from '../util/inspect';
1313

1414
let createPopper;
1515

16-
export default (config) => ({
16+
export default config => ({
1717
focusedOptionIndex: null,
1818
filterable: false,
1919
data: [],
@@ -33,11 +33,17 @@ export default (config) => ({
3333
labelField: 'label', // used for an "optgroup"'s label
3434
optionsField: 'options', // used when creating "optgroups"
3535
popper: null,
36+
_wire: null, // for when in a livewire component
3637
...config,
3738

3839
get buttonDisplay() {
3940
if (this.multiple) {
40-
let optionDisplay = this.optionDisplay(this.value[0]);
41+
let optionDisplay;
42+
try {
43+
optionDisplay = this.optionDisplay(this.value[0]);
44+
} catch (e) {
45+
optionDisplay = '';
46+
}
4147

4248
if (this.value.length > 1) {
4349
optionDisplay += ` <span class="custom-select__select-count">+ ${this.value.length - 1}</span>`;
@@ -46,7 +52,11 @@ export default (config) => ({
4652
return optionDisplay;
4753
}
4854

49-
return this.optionDisplay(this.value);
55+
try {
56+
return this.optionDisplay(this.value);
57+
} catch (e) {
58+
return '';
59+
}
5060
},
5161

5262
get fieldNames() {
@@ -153,10 +163,7 @@ export default (config) => ({
153163
return this.value === value;
154164
},
155165

156-
/*
157-
* Calling initialize now so Alpine doesn't call the function twice.
158-
*/
159-
initialize($wire = null, $dispatch = null) {
166+
init() {
160167
createPopper = window.Popper ? window.Popper.createPopper : window.createPopper;
161168

162169
if (typeof createPopper !== 'function') {
@@ -181,7 +188,7 @@ export default (config) => ({
181188
}
182189

183190
this.$watch('value', value => {
184-
$dispatch && $dispatch('custom-select-value-changed', { id: this.selectId, value });
191+
this.$dispatch('custom-select-value-changed', { id: this.selectId, value });
185192
});
186193

187194
// Allow local filtering if user has not specified wire:filter on the custom select component.
@@ -192,8 +199,8 @@ export default (config) => ({
192199

193200
// If the user specifies a "wire:filter" method, attempt to call that method,
194201
// otherwise just perform local search.
195-
if (this.wireFilter && $wire) {
196-
$wire[this.wireFilter](value)
202+
if (this.wireFilter && this._wire) {
203+
this._wire[this.wireFilter](value)
197204
.then(data => {
198205
this.data = normalizeOptions(data, this.fieldNames);
199206
this.options = this.data;
@@ -212,20 +219,20 @@ export default (config) => ({
212219
.filter(o => ! this.isOptgroup(o) && (String(o.value).toLowerCase().includes(lowerCasedSearch) || o.text.toLowerCase().includes(lowerCasedSearch)));
213220
});
214221

215-
if ($wire) {
222+
if (this._wire) {
216223
// Wire listeners are useful for selects whose options depend on other selects. On the livewire component,
217224
// user can emit an event with the options that should be shown in the dependant select based on some
218225
// criteria.
219226
this.wireListeners.forEach(listener => {
220-
$wire.on(listener, data => {
227+
this._wire.on(listener, data => {
221228
this.data = normalizeOptions(data, this.fieldNames);
222229
this.options = this.data;
223230
});
224231
});
225232
}
226233

227234
// Emit our value changed event right away for any listeners...
228-
$dispatch && $dispatch('custom-select-value-changed', { id: this.selectId, value: this.value });
235+
this.$dispatch('custom-select-value-changed', { id: this.selectId, value: this.value });
229236
},
230237

231238
onMouseover(option, index) {
@@ -311,7 +318,8 @@ export default (config) => ({
311318

312319
let option = this.options.find(o => o.value === value);
313320

314-
if (! option && this.multiple && this.selectedOption.length > 0) {
321+
// First time this runs, selectedOption may be null, maybe a bug?
322+
if (! option && this.multiple && (this.selectedOption || []).length > 0) {
315323
option = this.selectedOption[0];
316324
} else if (! option && this.selectedOption && this.selectedOption.value === value) {
317325
option = this.selectedOption;

resources/views/components/inputs/custom-select.blade.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22
{{ $configToJson() }}
33
@if ($attributes->hasStartsWith('wire:model'))
44
value: @entangle($attributes->wire('model')),
5+
_wire: $wire,
56
@else
67
value: {{ $selectedKeyToJS() }},
78
@endif
89
@if ($attributes->hasStartsWith('wire:filter'))
910
wireFilter: '{{ $attributes->wire('filter')->value() }}',
1011
@endif
1112
})"
12-
x-init="$nextTick(() => { initialize({{ $attributes->hasStartsWith('wire:model') ? '$wire' : 'null' }}, $dispatch) })"
13-
x-on:click.outside="close()"
14-
x-on:keydown.escape="close()"
15-
x-on:keydown.enter.stop.prevent="onEnter()"
16-
x-on:keydown.arrow-up.prevent="focusPreviousOption()"
17-
x-on:keydown.arrow-down.prevent="focusNextOption()"
18-
x-on:keydown.home.prevent="onHome()"
19-
x-on:keydown.end.prevent="onEnd()"
20-
x-on:keydown.tab="close()"
13+
x-on:click.outside="close"
14+
x-on:keydown.escape="close"
15+
x-on:keydown.enter.stop.prevent="onEnter"
16+
x-on:keydown.arrow-up.prevent="focusPreviousOption"
17+
x-on:keydown.arrow-down.prevent="focusNextOption"
18+
x-on:keydown.home.prevent="onHome"
19+
x-on:keydown.end.prevent="onEnd"
20+
x-on:keydown.tab="close"
2121
wire:ignore.self
2222
class="{{ $getContainerClass() }}"
2323
{{ $extraAttributes }}

src/Components/Inputs/CustomSelect.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class CustomSelect extends Select
1515
public null|string $placeholder;
1616
public null|string $emptyText;
1717

18+
protected bool $jsonEncodeArrayValues = false;
19+
1820
public function __construct(
1921
public null | string $name = null,
2022
public null | string $id = null,
@@ -105,7 +107,7 @@ public function selectedKeyToJS(): mixed
105107

106108
return is_string($this->selectedKey)
107109
? "'{$this->selectedKey}'"
108-
: $this->selectedKey;
110+
: json_encode($this->selectedKey);
109111
}
110112

111113
public function getContainerClass(): string

src/Components/Inputs/Input.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ class Input extends BladeComponent
1414
use HandlesValidationErrors;
1515
use HasAddons;
1616

17+
/*
18+
* Normally we want arrays to be encoded, but some components don't need that, like CustomSelect.
19+
*/
20+
protected bool $jsonEncodeArrayValues = true;
21+
1722
/** @var string */
1823
public const DEFAULT_INLINE_ADDON_PADDING = 'pl-16 sm:pl-14';
1924

@@ -53,7 +58,7 @@ public function __construct(
5358
$this->trailingAddonPadding = $trailingAddonPadding;
5459
$this->trailingIcon = $trailingIcon;
5560

56-
if (is_array($this->value)) {
61+
if (is_array($this->value) && $this->jsonEncodeArrayValues) {
5762
$this->value = json_encode($this->value);
5863
}
5964
}

0 commit comments

Comments
 (0)