8

I'm trying to implement custom select component with Vuejs 2. As stated in the documentation that i should not modify value props directly and suggested to use event to pass the selected data to parent component. I'm having issue when the option value is an object and got [Object object] instead.

here's my select component template:

<div :class="inputLength">
        <select :id="id"
                :value="value"
                @change="setValue($event.target.value)"
                :multiple="multiple"
                class="selectpicker">
            <option value="">Nothing selected.</option>
            <option :selected="option == value" v-for="option in options"
                    :value="option">
                {{ option[label] }}
            </option>
        </select>
        <span v-if="error.any()" class="help-block" v-text="error.all()"></span>

</div>

and here's the script part:

export default {
    props: {
        value: {
            default() {
               return ''
            }
        },
        options: {
            type: Array,
            require: true
        },
        ...
    },
    methods: {
        setValue(val) {
            this.error.clear();
            this.$emit('input', val);
        }
    }
}

and here's the parent component

<input-select-horizontal
    v-model="form.category"
    :label-class="{'col-md-4': true}"
    input-length="col-md-8"
    :options="categories.all()"
    label="name"
    :error="form.errors.get('category_id')">
<span slot="label">Category <span class="required" aria-required="true">*</span></span>

the options:

[
    {
        id: 1,
        name: 'Category 1',
        description: 'desc 1'
    },
    {
        id: 2,
        name: 'Category 2',
        description: 'desc 2'
    },
    ...
]

I'm expecting the

form.category = {
    id: 1,
    name: "Category 1",
    description: "desc 1"
}

but got [Object object]

did i miss something?

3 Answers 3

8

Your problem lies here:

<option v-for="option in options" :value="option">
  {{ option[label] }}
</option>

You're taking a whole object and assigning it to the value attribute of the option element. This won't work, because the value attribute has to be a string. So the object is converted to [Object object].

You should try using :value="option.id", the ID value should get through to the parent component normally and you can use it to find the right category.

Sign up to request clarification or add additional context in comments.

2 Comments

hi, instead of using :value="option.id" then use it as a reference to find the right category, I used options[event.target.selectedIndex - 1] so the component could handle non object options.
this answer is wrong. Vuejs supports binding objects to values of <option> tags. Indeed it seems to appear as "[object: Object]" when inspecting, but it works (as long as we work with the exact same object instances consistently).
0

As mzgajner mentioned, you can't bind an object because it will convert it to a string. What you can do however, is to convert your object to a base64 string in the options component, and then decode it again in the select component.

For example: Component CustomOption

<template>
  <option v-bind="{ ...$attrs, value: innerValue }" v-on="$listeners">
    <slot>
      {{ label || $attrs.value }}
    </slot>
  </option>
</template>

<script>
export default {
  props: {
    label: [String, Number, Boolean],
  },
  computed: {
    innerValue() {
      return btoa(JSON.stringify(this.$attrs.value));
    },
  },
};
</script>

Component CustomSelect

<template>
  <select
    :value="innerValue"
    v-bind="$attrs"
    v-on="{
      ...$listeners,
      input: onInput,
    }"
  >
    <slot></slot>
  </select>
</template>

<script>
export default {
  props: {
    value: null
  },
  computed: {
    innerValue() {
      return btoa(JSON.stringify(this.value));
    },
  },
  methods: {
    onInput(e) {
      let value = JSON.parse(atob(e.target.value));
      this.$emit('input', value);
    },
  },
};
</script>

Comments

-2
https://www.npmjs.com/package/stf-vue-select


<stf-select v-model="value" style="width: 300px; margin: 0 auto">
      <div slot="label">Input address</div>
      <div slot="value">
        <div v-if="value">
           <span>{{value.address}} (<small>{{value.text}}</small>)</span>
        </div>
      </div>
      <section class="options delivery_order__options">
          <stf-select-option  
           v-for="item of list" :key="item.id"
           :value="item"
           :class="{'stf-select-option_selected': item.id === (value && value.id)}" 
           >
              <span>{{item.text}} (<small>{{item.address}}</small>)</span>
          </stf-select-option>
      </section>
    </stf-select>

1 Comment

Although this may answer the question, code-only answers are frowned upon. Please also provide an explanation to OP to explain your answer. How to Answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.