Home > OS >  custom vue 3 form select not emit the correct model value
custom vue 3 form select not emit the correct model value

Time:12-02

I have created a select form component:

<template>
    <div class="col">
        <div class="row mb-4">
            <label class="col-sm-4 col-form-label col-form-label-sm">{{ label }}</label>
            <div class="col-sm-8">
                <select
                    class="form-select form-select-sm"
                    :class="{'is-invalid': error}"
                    :disabled="disabled"
                    :value="modelValue"
                    @change="updateSelect"
                >
                    <option
                        v-for="(option, index) in options"
                        :value="option.id ? option.id : (option.value ? option.value : option)"
                        :key="option.id ? option.id : index"
                    >
                        {{ option.name ? option.name : option }}
                    </option>
                </select>
                <div class="invalid-feedback" v-if="error"> {{ error }}</div>
            </div>
        </div>
    </div>
</template>

<script>

export default {
    name: "SelectForm",
    props: {
        label: {
            type: String,
            default: "",
        },
        modelValue: {
            type: [String, Number, Boolean],
            default: "",
        },
        error: {
            type: String,
            default: ""
        },
        disabled: {
            type: Boolean,
            default: false
        },
        options: {
            type: Object
        }
    },
    setup(props, { emit }) {
        const updateSelect = (event) => {
            emit("update:modelValue", event.target.value)
        }

        return {
            updateSelect
        }
    }
}
</script>

<style scoped>

</style>

Options can be for ex:

['Test 1', 'Test 2']
[{id: 1, name: 'Test 1'}]
[{value: 'test1', name: 'Test 1'}]

So in the main component I have this:

<select-form label="Status" :options="userStatuses" v-model="isActive"/>

where userStatuses object is this:

const userStatuses = ref([
   {name: 'Active', value: true},
   {name: 'Inactive', value: false}
])

The problem is when selecting a value 'Active' it sets the isActive model as "true" (as String - and I need as it is - boolean) and for Inactive => Object (this is what it says in Vue dev tools)

I guess the problem is when returning back the model value

emit("update:modelValue", event.target.value)

I am not sure if I done it correct.

Anyone know how to solve this ?

CodePudding user response:

I have made some changes in updateSelect function and cast the value if it is boolean or number ... and set that value on update:

const updateSelect = (event) => {
   let value = event.target.value;
   if(value === 'true') { value = true }
   if(value === 'false') { value = false }
   if(!isNaN(parseInt(value))) { value = parseInt(value) }
   emit("update:modelValue", value)
}

CodePudding user response:

This line seems to cause the "Inactive" to return object and "Active" to return a string:

:value="option.id ? option.id : (option.value ? option.value : option)"

Since {name: 'Inactive', value: false} doesn't have an id and has a falsy value it will set the entire option object as value of the option.

You can rewrite it as:

:value="typeof(option) === 'string' ? option : option.id || option.value"

So you'll always get either "true" or "false" in this use-case. However, I believe that the event.target.value for select will return string either way so you'll need to also change this:

emit("update:modelValue", event.target.value)

to

emit("update:modelValue", event.target.value === "true")
  • Related