|
| 1 | +# Changes to `v-model` on custom components |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +In terms of what has changed, at a high level: |
| 6 | + |
| 7 | +- When used on custom components, `v-model` prop and event default names are changed: |
| 8 | + - prop: `value` -> `modelValue`; |
| 9 | + - event: `input` -> `update:modelValue`; |
| 10 | +- Multiple `v-model` bindings on the same component are possible now; |
| 11 | +- **BREAKING:** `v-bind`'s `.sync` modifier and component `model` option are removed and replaced with an argument on `v-model`; |
| 12 | +- **NEW:** Added the ability to create custom `v-model` modifiers. |
| 13 | + |
| 14 | +For more information, read on! |
| 15 | + |
| 16 | +## Introduction |
| 17 | + |
| 18 | +In Vue 2, the `v-model` directive required developers to always use the `value` prop. And if developers required different props for different purposes, they would have to resort to using `v-bind.sync`. In addition, this hard-coded relationship between `v-model` and `value` led to issues with how native elements and custom elements were handled. |
| 19 | + |
| 20 | +In 2.2 we introduced the `model` component option that allows the component to customize the prop and event to use for `v-model`. However, this still only allowed a single `v-model` to be used on the component. |
| 21 | + |
| 22 | +With Vue 3, the API for two-way data binding is being standardized in order to reduce confusion and to allow developers more flexibility with the `v-model` directive. |
| 23 | + |
| 24 | +## Previous Syntax |
| 25 | + |
| 26 | +In v2, using a `v-model` on a component was an equivalent of passing a `value` prop and emitting an `input` event: |
| 27 | + |
| 28 | +```html |
| 29 | +<ChildComponent v-model="pageTitle" /> |
| 30 | + |
| 31 | +<!-- would be shorthand for: --> |
| 32 | + |
| 33 | +<ChildComponent :value="pageTitle" @input="pageTitle = $event" /> |
| 34 | +``` |
| 35 | + |
| 36 | +If we wanted to change prop or event names to something different, we would need to add a `model` option to `ChildComponent` component: |
| 37 | + |
| 38 | +```html |
| 39 | +<!-- ParentComponent.vue --> |
| 40 | + |
| 41 | +<ChildComponent v-model="pageTitle" /> |
| 42 | +``` |
| 43 | + |
| 44 | +```js |
| 45 | +// ChildComponent.vue |
| 46 | + |
| 47 | +export default { |
| 48 | + model: { |
| 49 | + prop: 'title', |
| 50 | + event: 'change' |
| 51 | + }, |
| 52 | + props: { |
| 53 | + // this allows using the `value` prop for a different purpose |
| 54 | + value: String, |
| 55 | + // use `title` as the prop which take the place of `value` |
| 56 | + title: { |
| 57 | + type: String, |
| 58 | + default: 'Default title' |
| 59 | + } |
| 60 | + } |
| 61 | +} |
| 62 | +``` |
| 63 | + |
| 64 | +So, `v-model` in this case would be a shorthand to |
| 65 | + |
| 66 | +```html |
| 67 | +<ChildComponent :title="pageTitle" @change="pageTitle = $event" /> |
| 68 | +``` |
| 69 | + |
| 70 | +### Using `v-bind.sync` |
| 71 | + |
| 72 | +In some cases, we might need "two-way binding" for a prop (sometimes in addition to existing `v-model` for the different prop). To do so, we recommended emitting events in the pattern of `update:myPropName`. For example, for `ChildComponent` from the previous example with the `title` prop, we could communicate the intent of assigning a new value with: |
| 73 | + |
| 74 | +```js |
| 75 | +this.$emit('update:title', newValue) |
| 76 | +``` |
| 77 | + |
| 78 | +Then the parent could listen to that event and update a local data property, if it wants to. For example: |
| 79 | + |
| 80 | +```html |
| 81 | +<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" /> |
| 82 | +``` |
| 83 | + |
| 84 | +For convenience, we had a shorthand for this pattern with the .sync modifier: |
| 85 | + |
| 86 | +```html |
| 87 | +<ChildComponent :title.sync="pageTitle" /> |
| 88 | +``` |
| 89 | + |
| 90 | +## Current Syntax |
| 91 | + |
| 92 | +In v3 `v-model` on the custom component is an equivalent of passing a `modelValue` prop and emitting an `update:modelValue` event: |
| 93 | + |
| 94 | +```html |
| 95 | +<ChildComponent v-model="pageTitle" /> |
| 96 | + |
| 97 | +<!-- would be shorthand for: --> |
| 98 | + |
| 99 | +<MyBook :modelValue="pageTitle" @update:modelValue="pageTitle = $event" /> |
| 100 | +``` |
| 101 | + |
| 102 | +### `v-model` arguments |
| 103 | + |
| 104 | +To change a model name, instead of a `model` component option, now we can pass an _argument_ to `v-model`: |
| 105 | + |
| 106 | +```html |
| 107 | +<ChildComponent v-model:title="pageTitle" /> |
| 108 | + |
| 109 | +<!-- would be shorthand for: --> |
| 110 | + |
| 111 | +<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" /> |
| 112 | +``` |
| 113 | + |
| 114 | + |
| 115 | + |
| 116 | +This also serves as a replacement to `.sync` modifier and allows us to have multiple `v-model`s on the custom component. |
| 117 | + |
| 118 | +```html |
| 119 | +<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" /> |
| 120 | + |
| 121 | +<!-- would be shorthand for: --> |
| 122 | + |
| 123 | +<ChildComponent |
| 124 | + :title="pageTitle" |
| 125 | + @update:title="pageTitle = $event" |
| 126 | + :content="pageContent" |
| 127 | + @update:content="pageContent = $event" |
| 128 | +/> |
| 129 | +``` |
| 130 | + |
| 131 | +### `v-model` modifiers |
| 132 | + |
| 133 | +In addition to v2 hard-coded `v-model` modifiers like `.trim`, now v3 supports custom modifiers: |
| 134 | + |
| 135 | +```html |
| 136 | +<ChildComponent v-model.capitalize="pageTitle" /> |
| 137 | +``` |
| 138 | + |
| 139 | +Read more about custom `v-model` modifiers in the [Custom Events](../component-custom-events.html#handling-v-model-modifiers) section. |
| 140 | + |
| 141 | +## Next Steps |
| 142 | + |
| 143 | +For more information on the new `v-model` syntax, see: |
| 144 | + |
| 145 | +- [Using `v-model` on Components](../component-basics.html#using-v-model-on-components) |
| 146 | +- [`v-model` arguments](../component-custom-events.html#v-model-arguments) |
| 147 | +- [Handling `v-model` modifiers](../component-custom-events.html#v-model-arguments) |
0 commit comments