Ensuring the preservation of value type while making a Vue component function with v-model

Issue

When using v-model on an HTML <select>, the v-model function assigns the selected value while preserving the data types - if a number is bound to an <option>, the model property will also be assigned as a number, and if an Object is bound, it's set accordingly.

<script>
export default {
  data: {
    options: [5, 10, 15, 'text', { 'description': 'I am an Object' }],
  }
};
</script>

<template>
  <select v-model="model">
    <option
      v-for="option in options"
      :value="option"
    >
      {{ option }}
    </option>
  </select>
<template>

I have created a custom component called <base-select> that wraps the usage of the <select> tag. I'm trying to replicate the same behavior for the v-model on this component, but I'm facing an issue where the types are not preserved - the values are consistently returned as Strings, even when binding numbers or objects.

//// BaseSelect.vue

<script>
export default {
  props: {
    options: {
      type: Array,
      required: true
    },
    value: {
      required: true
    }
  },
};
</script>
<template>
  <select
    :value="value"
    @input="$emit('input', $event.target.value)"
  >
    <option
      v-for="option in options"
      :value="option"
    >
      {{ option }}
    </option>
  </select>
</template>

//// App.vue

<script>
  @import 'BaseSelect' from './BaseSelect';

  export default {
    components: {
      BaseSelect,
    },
    data: {
      options: [5, 10, 15, 'text', { 'description': 'I am an Object' }],
    }
  };
</script>
<template>
  <base-select
    v-model="model"
    :options="options"
  />
<template>

Fiddle

To see this behavior in action, visit: http://jsfiddle.net/4o67pzLs/14/

The first select retains the data types of the values bound to the model, whereas the second one always converts values to Strings.

Query

Is there a way to implement v-model on a custom component while preserving data types? If so, how can this be achieved?

Answer №1

After collaborating with @RobertKusznier, we successfully achieved the following:

  • Connecting the select element to a computed property in the component using v-model
  • Implementing a getter and setter for the computed property
  • The getter retrieves the component's value
  • The setter triggers the change event

This solution maintains the type of the selected option's value without altering the component's value.

Credit goes to @RobertKusznier for recommending against mutating the component's value.

let baseSelect = {
props: {
  options: {
    type: Array,
      required: true
    },
    value: {
    required: true
    }
  },
  
  computed: {
  valueCopy: {
    get() {
      return this.value;
      },
      set(value) {
      this.$emit('input', value);
      }
    }
  },
  
  template: `
  <select
      v-model="valueCopy"
    >
      <option
        v-for="option in options"
        :value="option"
      >
        {{ option }}
      </option>
    </select>
  `,
};

new Vue({
el: '#app',
  components: {
  baseSelect
  },
  data: {
  model: 5,
    options: [5, 10, 15, 'text', new Date()]
  },
  template: `
    <div>
      <select v-model="model">
        <option
          v-for="option in options"
          :value="option">
            {{ option }}
        </option>
      </select>
      
      <base-select
        v-model="model"
        :options="options"
        :sister="10"
      />
      
      <p>model: {{ model }}</p>
      <p>typeof model: {{ typeof model }}</p>
    </div>
  `
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app"></div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Positioning a Three.js static CSS2DObject with respect to the camera's perspective

I am currently working on a unique program visualizer that utilizes Three.js to showcase various aspects of a program to the user. One crucial feature of this visualizer is allowing users to click on specific objects to view additional information about th ...

Error message encountered in PHP due to an undefined index

My goal is to add items from a form to a table named products. The form layout can be seen here: https://i.stack.imgur.com/f9e08.png The "Add more suppliers: +" link adds a new row to the form when clicked. The corresponding script for this action is as ...

What is the best way to dynamically pass JSON object values to PHP?

Greetings, I am new to JSON and Ajax. Although my question may seem trivial, I believe that even the simplest inquiries are crucial in the learning process. My dilemma involves passing two parameters (giorno and periodo) via Ajax: For example: 'gior ...

When building with Vue/Webpack, it is better to duplicate the symlink instead of the entire

I'm encountering an issue in my Vue project where I need to copy a symlink from either the /src folder or /public folder to the /dist folder during or after the build process. The vue.config.js file has been configured as follows... const path = requi ...

Obtain access to a Java list of objects using JavaScript or ExtJS

Interested in working on a list of objects with JavaScript, potentially using ExtJS as well in the project. There are two lists in the JSP file (modelList and categoryList) forwarded by the controller, and the goal is to access data in both lists. Is this ...

What could be causing Mathjax to generate multiple copies?

I have integrated MathJax into my application to render MathML. The code snippet below is used to ensure that the MathML is typeset properly: $rootScope.$watch(function() { MathJax.Hub.Queue(["Typeset", MathJax.Hub]); return true; }); However, I ...

Ways to ensure that the height of the second row in the second column matches that of the first column

My current layout design is causing an issue where the lower green box extends beyond the total height of the entire box. I've provided a rough version of my code on codepen. Using the Bulma framework, my goal is to align the height of the left column ...

Master the art of directing your attention to a list element with ease using the tab function and jQuery

I've been tasked with creating a questionnaire for a client. They want the current active question to be displayed at 100% opacity, while the inactive questions should be at 20% opacity. Currently, when the page loads, all questions are dimmed to 20% ...

Mute Vue alerts during unit testing

I have been attempting to silence warnings in my tests by following the configuration provided here: https://vue-test-utils.vuejs.org/api/config.html#silent. The configuration is as follows: import { config } from '@vue/test-utils'; // setting ...

Unit testing a React component by using the `renderToString` method

Context My React application is built using the React Starter Kit. In the server.js file, components are rendered using renderToStaticMarkup and then passed to the Html component, which includes it using dangerouslySetInnerHTML as shown here. I am facing ...

What are the signs indicating that I've reached the threads limit set in Node.js?

My current configuration includes a thread pool size of 25. process.env.UV_THREADPOOL_SIZE = 25; How can I verify at runtime that all the threads have been used up? Is there a method to detect when all defined threads have been utilized when a new reque ...

The functionality of item.classList.toggle() in HTML+CSS+JS fails to execute

I have been working on a program that aims to flip a card when it is clicked. The JavaScript code I have written for this functionality is as follows: /* Card flipping onclick */ import "./Stylesheets/FlipCardStyle.css" var cards = document.quer ...

Vanilla JS method for resetting Bootstrap 5 client-side validation when focused

I'm currently exploring Bootstrap 5's client-side validation feature. However, I've encountered a usability issue with the is-invalid class. After clicking the submit button, this class persists until the correct input is entered. I would li ...

The `mouseenter` event handler fails to trigger properly on its initial invocation

As I work on a function to remove a CSS class display:hidden; when the mouse enters a specific part of the DOM to reveal a menu, I encounter an issue. Upon loading the page and hovering over the designated area for the first time, the event fails to trigge ...

Sorting a targeted section of an already organized 2D Array based on updated values, solely if the initial sorted values align in Javascript

A challenging scenario I need help with involves an array containing objects, each with a score and a rank as shown below: [ { "score": 20, "rank": 12 }, { "score": 20, "rank": 7 }, { "score": 34, "rank": 4 } ] To begin w ...

Is sending a stream to a variable the best option, or could there be another solution

Is there a way to pipe stream data to a variable? The writable stream examples mentioned in this documentation include: HTTP requests on the client side HTTP responses on the server side Zlib streams Crypto streams TCP sockets Child process stdin Process ...

Displaying current location on Google maps with generated code and adding a new marker by clicking in PHP: Firefox

I am currently working on a code that will display a marker at the current location and also add a new marker whenever the screen is touched or clicked. I have been trying to make it work with the code I found online, but it has been a bit of a challenge ...

Ways to show dynamic text according to slider adjustments

I am struggling with adding an if condition to my form that includes a horizontal slider. My goal is to display text based on the position of the slider. Can someone offer some guidance on this, please? Here's my HTML code snippet: <form method=" ...

Pytest is not able to locate any elements on the webpage, yet the same elements can be easily found using the console

When using CSS or XPath in the console (F12), I am able to locate the element on the page. $$("span.menu-item[data-vars-category-name='Most Popular']") However, when trying to find the same elements with Selenium (pytest) using: driver.find_el ...

Everything you need to know about utilizing base URLs with axios

I successfully deployed my backend on Heroku, tested the endpoints using Postman, and updated the Heroku endpoint in the .env file of my React JS application. However, despite making these changes, the application still doesn't work. What could be cau ...