skip to Main Content

In the docs for vue’s v-model modifiers, they give this example and there is a playground link as well.

<script setup>
const [model, modifiers] = defineModel({
  set(value) {
    if (modifiers.capitalize) {
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
    return value
  }
})
</script>

<template>
  <input type="text" v-model="model" />
</template>

This code can be edited so that the modifiers variable is now foo. What kind of pattern is this and how is this achievable (with pseudocode) since the value of const [model, foo] = ... is in a different scope than foo.capitalize?

<script setup>
const [model, foo] = defineModel({
//            ^^^
  set(value) {
    if (foo.capitalize) {
//      ^^^
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
    return value
  }
})
</script>

<template>
  <input type="text" v-model="model" />
</template>

2

Answers


  1. As stated in comments, the fact that you can change the variable name and achieve the same results, is expected: there is nothing special to the name model — it is just a name.

    What can be confusing is that the set method reads from a variable that is only defined and assigned a value in the same expression that set method occurs in.

    But realise that this set method is not yet called when defineModel is called. The foo (or model) variable will be initialised by this overall expression, but the set method is not called by this expression. This whole expression has already been evaluated and assigned to foo before the set method is ever called.

    NB: It would have been a problem if the defineModel function would itself call the set method of the given object. If that were the case, foo would be undefined, and an error would be triggered when evaluating foo.capitalize.

    As to the parsing of this code: the foo variable is declared, and its name is known for the set function, and can be parsed without issue.

    Example

    This principle is not specific for Vue. It is how things work in plain JavaScript.

    Here is a simple JavaScript example, where foo is assigned without destructuring (which was an irrelevant aspect), and set is called explicitly with some format function that is made available to foo:

    function create(obj) {
        console.log("executing: create()");
        return {
            capitalize: true,
            format(value) { return obj.set(value); }
        };
    }
    
    const foo = create({
        set(value) {
            console.log("executing: set()");
            if (foo.capitalize) value = value.toUpperCase();
            return value;
        }
    });
    console.log("foo was assigned");
    
    // Only now `set` will be called
    const value = foo.format("hello world");
    console.log(value);

    So, notice the order of the output that this snippet generates.

    Login or Signup to reply.
  2. This usage of defineModel macro roughly translates to:

    export default {
      props: {
        modelValue: null,
        modelModifiers: { default: () => ({}) }
      },
      emits: ['update:modelValue'],
      setup(props, { emit }) {
        const model = computed({
          get() {
            return props.modelValue;
          },
          set(value) {
            if (modifiers.value.capitalize) {
            ...
            emit('update:modelValue', value);
          }
        );
        const modifiers = computed(() => props.modelModifiers);
        ...
    

    defineModel returns an array of 2 elements (tuple) that can be destructured, so model and modifiers variable names are arbitrary.

    modifiers is accessed inside a computed at the time when model.value is changed, so this can’t cause modifiers is not defined error.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search