Skip to content

Commit

Permalink
Merge pull request #6 from bfiessinger/fix/multiple-null-value-on-mount
Browse files Browse the repository at this point in the history
Fix/multiple null value on mount
  • Loading branch information
bfiessinger authored Sep 1, 2021
2 parents 72dfb9e + bfca089 commit 4977afe
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 79 deletions.
5 changes: 4 additions & 1 deletion resources/views/default.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ class="{{ $styles['default'] }}"
</option>

@foreach($options as $option)
<option value="{{ $option['value'] }}">
<option
value="{{ $option['value'] }}"
{!! (json_decode($initValueEncoded) && $option['value'] == json_decode($initValueEncoded)) ? 'selected' : '' !!}
>
{{ $option['description'] }}
</option>
@endforeach
Expand Down
128 changes: 70 additions & 58 deletions resources/views/multiple.blade.php
Original file line number Diff line number Diff line change
@@ -1,90 +1,102 @@
<div
wire:model="value"
x-data="livewireSelectMultiSelectDropdown($el)"
x-init="loadOptions($el.querySelector('.livewire-select-input'))"
@livewireselectoptionsloaded="loadOptions($el.querySelector('.livewire-select-input'))"
class="w-full flex flex-col items-center"
@livewireselectoptionsloaded="loadOptions($el.querySelector('.livewire-select-input'));"
>
<select
x-show="false"
x-cloak
class="livewire-select-input {{ $styles['default'] }}"
multiple="true"
name="{{ $name }}"
wire:model="value"
class="livewire-select-input"
x-bind:value="selectedValues()"
multiple="true"
>
<option value="">
{{ $placeholder }}
</option>
@foreach($options as $option)
<option value="{{ $option['value'] }}" x-bind:selected="(selectedValues().indexOf('{{ $option['value'] }}') >= 0) ? 'true' : false;">
<option
value="{{ $option['value'] }}"
{{ (json_decode($initValueEncoded) && in_array($option['value'], json_decode($initValueEncoded))) ? 'selected="selected"' : '' }}
>
{{ $option['description'] }}
</option>
@endforeach
</select>
<div class="w-full block relative">
<div class="flex flex-col items-center relative">
<div x-on:click="open" class="w-full">
<div class="p-1 flex border border-gray-200 bg-white rounded">
<div class="flex flex-auto flex-wrap">
<template x-for="(option,index) in selected" :key="options[option].value">
<div class="flex justify-center items-center m-1 font-medium py-1 px-1 bg-white rounded bg-gray-100 border">
<div class="text-xs font-normal leading-none max-w-full flex-initial x-model=" options[option] x-text="options[option].text"></div>
<div class="flex flex-auto flex-row-reverse">
<div x-on:click.stop="remove(index,option)">
<svg class="fill-current h-4 w-4 " role="button" viewBox="0 0 20 20">
<path d="M14.348,14.849c-0.469,0.469-1.229,0.469-1.697,0L10,11.819l-2.651,3.029c-0.469,0.469-1.229,0.469-1.697,0

<div
class="w-full flex flex-col items-center"
>
<div class="w-full block relative">
<div class="flex flex-col items-center relative">
<div @click="open" class="w-full">
<div class="my-2 p-1 flex border border-gray-200 bg-white rounded">
<div class="flex flex-auto flex-wrap">
<template x-for="(option,index) in selected" :key="option">
<div class="flex justify-center items-center m-1 font-medium py-1 px-1 bg-white rounded bg-gray-100 border">
<div class="text-xs font-normal leading-none max-w-full flex-initial" x-model="options[option]" x-text="options[option].text"></div>
<div class="flex flex-auto flex-row-reverse">
<div @click.stop="remove(index,option); $dispatch('input', selectedValues())">
<svg class="fill-current h-4 w-4 " role="button" viewBox="0 0 20 20">
<path d="M14.348,14.849c-0.469,0.469-1.229,0.469-1.697,0L10,11.819l-2.651,3.029c-0.469,0.469-1.229,0.469-1.697,0
c-0.469-0.469-0.469-1.229,0-1.697l2.758-3.15L5.651,6.849c-0.469-0.469-0.469-1.228,0-1.697s1.228-0.469,1.697,0L10,8.183
l2.651-3.031c0.469-0.469,1.228-0.469,1.697,0s0.469,1.229,0,1.697l-2.758,3.152l2.758,3.15
C14.817,13.62,14.817,14.38,14.348,14.849z" />
</svg>
</div>
</div>
</div>
</template>
<div x-show="selected.length == 0" class="flex-1">
<input placeholder="Select a option" class="bg-transparent p-1 px-2 appearance-none outline-none h-full w-full text-gray-800" x-bind:value="selectedValues()">
</svg>

</div>
</div>
</div>
<div class="text-gray-300 w-8 py-1 pl-2 pr-1 border-l flex items-center border-gray-200">
<button type="button" x-show="isOpen() === true" x-on:click="open" class="cursor-pointer w-6 h-6 text-gray-600 outline-none focus:outline-none">
<svg version="1.1" class="fill-current h-4 w-4" viewBox="0 0 20 20">
<path d="M17.418,6.109c0.272-0.268,0.709-0.268,0.979,0s0.271,0.701,0,0.969l-7.908,7.83
c-0.27,0.268-0.707,0.268-0.979,0l-7.908-7.83c-0.27-0.268-0.27-0.701,0-0.969c0.271-0.268,0.709-0.268,0.979,0L10,13.25
L17.418,6.109z" />
</svg>
</button>
<button type="button" x-show="isOpen() === false" @click="close" class="cursor-pointer w-6 h-6 text-gray-600 outline-none focus:outline-none">
<svg class="fill-current h-4 w-4" viewBox="0 0 20 20">
<path d="M2.582,13.891c-0.272,0.268-0.709,0.268-0.979,0s-0.271-0.701,0-0.969l7.908-7.83
c0.27-0.268,0.707-0.268,0.979,0l7.908,7.83c0.27,0.268,0.27,0.701,0,0.969c-0.271,0.268-0.709,0.268-0.978,0L10,6.75L2.582,13.891z
" />
</svg>
</button>
</template>
<div x-show="selected.length == 0" class="flex-1">
<input placeholder="Select a option" class="bg-transparent p-1 px-2 appearance-none outline-none h-full w-full text-gray-800">
</div>
</div>
<div class="text-gray-300 w-8 py-1 pl-2 pr-1 border-l flex items-center border-gray-200">

<button type="button" x-show="isOpen() === true" @click="open" class="cursor-pointer w-6 h-6 text-gray-600 outline-none focus:outline-none">
<svg version="1.1" class="fill-current h-4 w-4" viewBox="0 0 20 20">
<path d="M17.418,6.109c0.272-0.268,0.709-0.268,0.979,0s0.271,0.701,0,0.969l-7.908,7.83
c-0.27,0.268-0.707,0.268-0.979,0l-7.908-7.83c-0.27-0.268-0.27-0.701,0-0.969c0.271-0.268,0.709-0.268,0.979,0L10,13.25
L17.418,6.109z" />
</svg>

</button>
<button type="button" x-show="isOpen() === false" @click="close" class="cursor-pointer w-6 h-6 text-gray-600 outline-none focus:outline-none">
<svg class="fill-current h-4 w-4" viewBox="0 0 20 20">
<path d="M2.582,13.891c-0.272,0.268-0.709,0.268-0.979,0s-0.271-0.701,0-0.969l7.908-7.83
c0.27-0.268,0.707-0.268,0.979,0l7.908,7.83c0.27,0.268,0.27,0.701,0,0.969c-0.271,0.268-0.709,0.268-0.978,0L10,6.75L2.582,13.891z
" />
</svg>

</button>
</div>
</div>
</div>
<div class="w-full px-4">
<div x-show.transition.origin.top="isOpen()" class="absolute shadow top-100 bg-white z-40 w-full left-0 rounded" x-on:click.away="close">
<div class="bg-white flex flex-col w-full overflow-y-auto max-h-64">
<template x-for="(option,index) in options" :key="index" class="overflow-auto">
<div class="cursor-pointer w-full border-gray-100 rounded-t border-b hover:bg-gray-100" @click="if (option.value) { select(index,$event) }">
<div class="flex w-full items-center p-2 pl-2 border-transparent border-l-2 relative">
<div class="w-full items-center flex justify-between">
<div class="mx-2 leading-6" x-model="option" x-text="option.text" x-bind:class="!option.value ? 'pointer-events-none text-gray-400': false"></div>
<div x-show="option.selected">
<svg class="fill-current w-4 h-4" viewBox="0 0 20 20">
<path d="M7.197,16.963H7.195c-0.204,0-0.399-0.083-0.544-0.227l-6.039-6.082c-0.3-0.302-0.297-0.788,0.003-1.087
C0.919,9.266,1.404,9.269,1.702,9.57l5.495,5.536L18.221,4.083c0.301-0.301,0.787-0.301,1.087,0c0.301,0.3,0.301,0.787,0,1.087
L7.741,16.738C7.596,16.882,7.401,16.963,7.197,16.963z" />
</svg>
</div>
</div>
</div>
<div x-show.transition.origin.top="isOpen()" class="absolute shadow top-100 bg-white z-40 w-full left-0 rounded" @click.away="close">
<div class="bg-white flex flex-col w-full overflow-y-auto h-64">
<template x-for="(option, index) in options" :key="index" class="overflow-auto">
<div class="cursor-pointer w-full border-gray-100 rounded-t border-b hover:bg-gray-100" @click="if (option.value) { select(index,$event); $dispatch('input', selectedValues()) }">
<div class="flex w-full items-center p-2 pl-2 border-transparent border-l-2 relative">
<div class="w-full items-center flex justify-between">
<div class="mx-2 leading-6" x-model="option" x-text="option.text"></div>
<div x-show="option.selected">
<svg class="fill-current w-4 h-4" viewBox="0 0 20 20">
<path d="M7.197,16.963H7.195c-0.204,0-0.399-0.083-0.544-0.227l-6.039-6.082c-0.3-0.302-0.297-0.788,0.003-1.087
C0.919,9.266,1.404,9.269,1.702,9.57l5.495,5.536L18.221,4.083c0.301-0.301,0.787-0.301,1.087,0c0.301,0.3,0.301,0.787,0,1.087
L7.741,16.738C7.596,16.882,7.401,16.963,7.197,16.963z"></path>
</svg>
</div>
</template>
</div>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
</div>
</div>

</div>
48 changes: 28 additions & 20 deletions src/LivewireSelect.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,13 @@ public function js($options = null) {
'livewire-select-multiple' => '<script>
function livewireSelectMultiSelectDropdown($el) {
// Select the node that will be observed for mutations
var innerSelectTargetNode = $el.querySelector(\'.livewire-select-input\');
var relatedSelectTargetNode = $el.querySelector(\'.livewire-select-input\');
// Options for the observer (which mutations to observe)
var innerSelectMutationObserverConfig = { attributes: true, childList: true, subtree: true };
var relatedSelectMutationObserverConfig = { attributes: true, childList: true, subtree: true };
// Callback function to execute when mutations are observed
const innerSelectMutationObserverCallback = function(mutationsList, observer) {
const relatedSelectMutationObserverCallback = function(mutationsList, observer) {
var hasUpdates = false;
Expand All @@ -273,15 +273,15 @@ function livewireSelectMultiSelectDropdown($el) {
}
if (hasUpdates) {
innerSelectTargetNode.dispatchEvent(new CustomEvent(\'livewireselectoptionsloaded\', { bubbles: true }));
relatedSelectTargetNode.dispatchEvent(new CustomEvent(\'livewireselectoptionsloaded\', { bubbles: true }));
}
};
// Create an observer instance linked to the callback function
var innerSelectMutationObserver = new MutationObserver(innerSelectMutationObserverCallback);
var relatedSelectMutationObserver = new MutationObserver(relatedSelectMutationObserverCallback);
// Start observing the target node for configured mutations
innerSelectMutationObserver.observe(innerSelectTargetNode, innerSelectMutationObserverConfig);
relatedSelectMutationObserver.observe(relatedSelectTargetNode, relatedSelectMutationObserverConfig);
return {
options: [],
Expand All @@ -291,13 +291,11 @@ function livewireSelectMultiSelectDropdown($el) {
close() { this.show = false },
isOpen() { return this.show === true },
select(index, event) {
if (!this.options[index].selected) {
this.options[index].selected = true;
this.options[index].element = event.target;
this.selected.push(index);
if (this.selected.indexOf(index) === -1) {
this.selected.push(index);
}
} else {
this.selected.splice(this.selected.lastIndexOf(index), 1);
this.options[index].selected = false
Expand All @@ -306,28 +304,38 @@ function livewireSelectMultiSelectDropdown($el) {
remove(index, option) {
this.options[option].selected = false;
this.selected.splice(index, 1);
},
loadOptions(select) {
const options = select.options;
loadOptions(selectEl) {
this.options = [];
const options = selectEl.options;
for (let i = 0; i < options.length; i++) {
let isSelected = false;
if (options[i].getAttribute(\'selected\') != null) {
if (this.selected.indexOf(i) === -1) {
this.selected.push(i);
}
isSelected = true;
}
this.options.push({
value: options[i].value,
text: options[i].innerText,
selected: options[i].getAttribute(\'selected\') != null ? options[i].getAttribute(\'selected\') : false
selected: isSelected
});
}
},
selectedValues() {
selectedValues(){
if (!this.options.length) {
return [];
}
return this.selected.map((option)=>{
return this.options[option].value;
});
})
}
}
}
</script>'
];
Expand Down

0 comments on commit 4977afe

Please sign in to comment.