Dealing with Vue 3: Remember that the v-model helper may not exhibit re

I created a small utility for handling vue 3 v-model binding, but I'm encountering an issue with reactivity. The internal changes are being emitted correctly, however, external changes are not being recognized. Interestingly, when I use the same computed function within my component, everything works as expected. How can I modify the utility to ensure full reactivity?

The utility:

import { computed, SetupContext, WritableComputedRef } from 'vue';

export const vModel = <T>(val: T, context: SetupContext, binding = 'modelValue'): WritableComputedRef<T> =>
    computed({
        get: () => val,
        set: (value) => {
            context.emit(`update:${binding}`, value);
        },
    });

The single file component (sfc):

<template>
    <div class="ms-deleteInput">
        <input class="ms-deleteInput__input" :label="label" v-model="inputVal" />
        <button @click="$emit('delete')" />
    </div>
</template>

<script lang="ts">
import { defineComponent, computed } from 'vue';

export default defineComponent({
    name: "deleteInput",
    props: {
        modelValue: {
            type: String,
            required: true,
        },
        label: {
            type: String,
            required: true,
        },
    },
    setup(props, context) {

        // This works
        const inputVal = computed({
            get: () => props.modelValue,
            set: (value) => {
                context.emit(`update:modelValue`, value);
            },
        });

        // This works too, but external changes of modelValue prop will not be detected:
        const inputVal = vModel(props.modelValue, context);

        return {
            inputVal,
        };
    },
});
</script>

Answer №1

When you fail to provide props to the helper, it will not be able to monitor changes in props within the computed property.

Make sure to pass props instead of props.modelValue to the helper:

const inputVal = initializeInput(props, context);

Revise the helper function as follows:

export const initializeInput = (props, binding) =>
computed({
    get: () => props.modelValue,
    set: (value) => {
        context.emit(`update:${binding}`, value);
    },
});

Answer №2

Appreciate your responses! I managed to resolve the issue using the following code:

import { computed, SetupContext, WritableComputedRef } from 'vue';

export const vModel = <T>(props: Record<string, T>, context: SetupContext, binding = 'modelValue'): WritableComputedRef<T> =>
    computed({
        get: () => props[binding],
        set: (value) => {
            context.emit(`update:${binding}`, value);
        },
    });

However, there seems to be a typing error. I'm encountering this error message:

Argument of type 'Readonly<LooseRequired<Readonly<{ modelValue?: unknown; label?: unknown; } & { modelValue: string; label: string; } & {}>>' is not assignable to parameter of type 'Record<string, string>'.
  'string & `on${string}`' and 'string' index signatures are incompatible.
    Type 'undefined' is not assignable to type 'string'.

I've experimented with various typings for the props in the function, but none appear to be accurate. I couldn't find a suitable method for typing in the vue documentation.

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

Is there a regular expression that can match any permutation of three digits?

Is it possible to create a regular expression that can determine if a string contains at least 3 digits, regardless of their order? (I would appreciate seeing the exact regex solution for this.) For example: abk2d5k6 //3 digits abk25k6d //also has 3 dig ...

Prioritize moving the JavaScript onload handler to the end of the queue

I am looking to include a JavaScript file at the very end of footer.php using a WordPress plugin. I attempted to do this with the 'add_action' Hook, but found that it is adding the JavaScript code near the </body> tag. add_action('wp_ ...

Top methods for handling special characters in a database

My mysql database is filled with json data that is then used in angularjs for display purposes. Some of the text within the database includes escaped quotes and double quotes, for example: Do you possess at least a bachelor\'s degree in child ...

Guide to extracting the outcomes of a promise array and populating them into a new array using Protractor

I am facing a challenge with transferring data from an array of promises generated by the following code: element.all(by.repeater('unit in units')). It seems to be difficult for me to store this data into another array: element.all(by.repeater(& ...

Using only THREE.Points, it is possible to dynamically calculate the camera position in three.js

My primary objective is to dynamically position the camera in such a way that my object remains visible. After researching, I came across this thread: How to Fit Camera to Object This article mentions the need for fov, height, and dist, variables which a ...

The Frida server experienced a crash when attempting to connect with an Android device

I'm attempting to conduct a penetration test and hook into my Android application method using Frida. However, when I execute the command from the Windows command prompt, my application crashes, and the intended method is not executed from the APK. I ...

Update the default base URL configuration for Axios

My axios configuration looks like this: const configAxios = { baseURL: 'http://127.0.0.1:8000/api', timeout: 30000, }; Vue.prototype.$axios = axios.create(configAxios) When making a call inside my component, I use the following syntax: this ...

Unable to render Google map on Vue CLI component

I am currently using the google map api to develop a basic application with vue.js. Interestingly, when I utilize a simple html and javascript setup with the api key, everything runs smoothly. However, once I transition the same process to vue, the map fai ...

Displaying an array of objects in the MUI Datagrid interface

I have integrated Redux into my project to retrieve data from the API, and this is a snapshot of the data structure: https://i.stack.imgur.com/jMjUF.png My current challenge lies in finding an effective way to display the information stored within the &a ...

Why is the count's answer 88?

<!DOCTYPE html> <html> <head> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"> </script> </head> <body> <div ng-app="myApp" ng-controller="personCtrl">{{count ...

The switch statement is not functioning properly when the button is pressed

I am trying to trigger an alert inside a switch statement when I click a button, but for some reason, it is not working. Even if I simply have an alert in the previous function, there is no output on my website. What could be causing this issue? Here is ...

Is there a way to specifically call the last promise in a loop?

I'm new to promises and could use some help. I have a situation where promises are resolving randomly, how can I ensure that the last promise in the loop is resolved after the full loop executes? For example, if this.selectedValues has 4 values, som ...

The background-size:cover property fails to function properly on iPhone models 4 and 5

I have taken on the task of educating my younger sister about programming, and we collaborated on creating this project together. Nicki Minaj Website However, we encountered an issue where the background image does not fully cover the screen when using b ...

A guide to resolving a sinonJS stub issue

Trying to stub a request with SinonJS has been a challenge for me. I set up the mock request before each test to use fake data, but it's not working as expected. I attempted to use Promise.resolve for resolving, but that didn't work out either. ...

"Error TS2339: The property specified does not exist within type definition", located on the input field

When a user clicks a specific button, I need an input field to be focused with its text value selected entirely to allow users to replace the entire value while typing. This is the markup for the input field: <input type="text" id="descriptionField" c ...

Experimenting with JavaScript within an Immediately Invoked Function Expression

My team leader is requesting that I encapsulate my JavaScript code within an Immediately-Invoked Function Expression (IIFE). However, I am struggling to use spyOn in my Jasmine spec file. How can I properly use spyOn on the following: (function(){ fu ...

Modifying the appearance of a dropdown input within a table footer using Vuetify

Our application utilizes Vuetify, with outlined text/select fields throughout: https://i.sstatic.net/UMAeH.png The table definition from the documentation is as follows: <v-data-table :headers="headers" :items="desserts" ...

Tips for styling the json response received from a servlet with jquery ajax

I am attempting to display a list of users returned from a servlet using jQuery ajax. The first script block is functioning well, successfully presenting the list of users in a formatted manner but experiencing issues passing form parameters such as text a ...

Combining Node.js with Backbone.js: A Perfect Pairing

After extensive research on both Node.js and Backbone.js, including tutorials and courses from Code School, I have a solid understanding of the roles these technologies play in web applications. However, my challenge lies in integrating Node.js and Backbo ...

What is the recommended approach for setting up a listener that detects multiple keyboard shortcuts such as Ctrl + [1-9]?

Query Is there a way to create a listener in Vue.js that can detect multiple shortcuts like Ctrl + [1-9] and then utilize the pressed shortcut value to trigger the changeRoute(pressedNumber) method? Illustration Ctrl + 1 is pressed changeRoute(pressedNum ...