I have a custom dropup component that I am building and I find myself running into some very weird issues with it. The biggest one being the blur event, which doesnt seem to be firing when I click outside of the input.
Basically I just want the options elements to hide on blur, if there is no localValue
then reset the component back to the Initial View and if there IS a localValue
set it to the Selected State, keeping the value in there.
I'm really not sure where I am going wrong here.
---Designs---
Initial State
Toggled State
Selected State
SelectModelInput
<template>
<div :key="buttonKey">
<div
style="position: relative; width: 100%"
tabindex="-1"
@blur="() => closeDropdown()"
>
<div @click="() => toggleDropup()">
<p
v-if="selectModelVersionIsVisible"
>
Select Model
</p>
<div v-if="!selectModelVersionIsVisible" >
<p >OP-REAL</p>
<input
v-model="localValue"
:
type="text"
placeholder="Type to Search"
/>
<button
v-if="localValue"
:
@click="() => clearLocalVal()"
>
<svg
style="width: 18px"
xmlns="http://www.w3.org/2000/svg"
width="100%"
height="100%"
viewBox="0 0 24 24"
fill="none"
stroke="#A5B0CB"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
</div>
<Transition name="fade">
<div
v-if="optionsAreVisible && filteredOptions.length !== 0"
>
<a
v-for="option in filteredOptions"
:key="option.model"
>
<div @click="selectOption(option.model)">
<p >{{ option.model }}</p>
<p >{{ option.date }}</p>
</div>
</a>
</div>
</Transition>
</div>
</div>
</template>
<script>
import { computed, defineComponent, ref, watch } from "vue";
export default defineComponent({
emit: ["input"],
props: {
value: { type: String },
models: {
type: Array,
default: () => [
{ model: "Test v1", date: "Jul.5.2022" },
{ model: "Test v2", date: "Jul.6.2022" },
{ model: "Test v3", date: "Jul.8.2022" },
],
},
},
setup(props, { emit }) {
const localValue = ref(props.value);
watch(localValue, (newVal) => {
emit("input", newVal);
});
const buttonKey = ref(0);
const optionsAreVisible = ref(false);
const selectModelVersionIsVisible = ref(true);
const options = ref(props.models);
const filteredOptions = computed(() => {
const filteredOptions = options.value.filter((option) =>
option.model.toLowerCase().includes(localValue.value?.toLowerCase())
);
return filteredOptions;
});
function toggleDropup() {
console.log("toggle Dropup");
optionsAreVisible.value = true;
selectModelVersionIsVisible.value = false;
}
function selectOption(option) {
console.log(`option → `, option);
localValue.value = option;
optionsAreVisible.value = false;
selectModelVersionIsVisible.value = false;
}
function closeDropdown() {
console.log(`localValue → `, localValue.value);
console.log("ping");
optionsAreVisible.value = true
}
function clearLocalVal() {
buttonKey.value ;
selectModelVersionIsVisible.value = true;
optionsAreVisible.value = false;
localValue.value = "";
}
return {
options,
optionsAreVisible,
selectModelVersionIsVisible,
toggleDropup,
filteredOptions,
localValue,
selectOption,
clearLocalVal,
buttonKey,
closeDropdown,
};
},
});
</script>
<style lang="sass" scoped>
button
background: none
border: none
p
padding: 0
margin: 0
::placeholder
font-style: italic
line-height: 0
color: #A5B0CB
._input
all: unset
position: relative
display: flex
justify-content: center
align-items: center
min-height: 2rem
min-width: 212px
background: #161a24
border-radius: 1rem
&:hover,
&:focus
box-shadow: 0 0 0 1px #3867D0
&-active
display: flex
justify-content: center
align-items: center
// padding-right: 2rem
&-select-model
// padding: 6px 0
color: #A5B0CB
font-size: 1rem
font-weight: 300
&-op-real
display: flex
justify-content: center
align-items: center
height: 100%
border-top-left-radius: 1rem
border-bottom-left-radius: 1rem
padding: 0 10px
background: #202634
font-size: 12px
font-weight: bold
letter-spacing: 0.96px
padding: 8px 10px
user-select: none
&-input
all: unset
font-size: 14px
text-align: center
color: #A5B0CB
padding: 6px 0px
padding-right: 2rem
flex: 1
border-top-right-radius: 1rem
border-bottom-right-radius: 1rem
&:focus::placeholder
color: transparent
&-delete
position: absolute
bottom: 50%
transform: translateY(50%)
right: 0
display: flex
justify-content: center
padding: 0
padding-right: 8px
._bg-change
background-color: #202634
._hide
visibility: hidden
._options
position: absolute
bottom: 100%
left: 30%
z-index: 100
display: flex
flex-direction: column
list-style-type: none
padding: 0.5rem 1rem
gap: 0.25rem
background-color: #2C2B30
border: 1px solid #727275
border-radius: 0.5rem
._option
background-color: transparent
font-size: 0.875rem
line-height: 1.25rem
font-weight: 400
white-space: nowrap
width: 100%
&-inner
width: 100%
display: flex
justify-content: space-between
padding: 0.25rem
cursor: pointer
&:hover
background-color: #3582F5
border-radius: 0.25rem
&-model
font-size: 14px
color: #fff
margin-right: 2.5rem
&-date
font-size: 12px
color: #B2B4B9
.fade-enter-active,
.fade-leave-active
transition: opacity 300ms
.fade-enter,
.fade-leave-to
opacity: 0
</style>
App.vue
<template>
<div >
<SelectModelInput
v-model="text"
:models="modelsFromDev"
/>
<br />
<span style="color: white">{{ text }}</span>
</div>
</template>
<script>
import { defineComponent, ref } from "vue";
import SelectModelInput from "./components/SelectModelInput.vue";
export default defineComponent({
setup() {
const text = ref("");
const modelsFromDev = [
{ model: "Test v4", date: "Jul.5.2022" },
{ model: "Test v5", date: "Jul.6.2022" },
{ model: "Test v6", date: "Jul.8.2022" },
];
return { text, modelsFromDev };
},
components: { SelectModelInput },
});
</script>
<style lang="sass" scoped>
body
padding: 0
margin: 0
._wrapper
color: white
display: flex
flex-direction: column
justify-content: center
align-items: center
width: 100vw
height: 100vh
background: #283044
</style>
CodePudding user response:
Showing the options should be tied to clicking on the "Type to Search" <input>
. When this <input>
loses focus then set options visible to false. Using your code I also had to make functions to separately toggle selectModelVersionIsVisible and optionsAreVisible: codesandbox
Also regarding one of your other comments, clicking the "X" button can be made to clear localValue by just setting localValue = ''
on click which is also in my sandbox. Don't need to use :key