Skip to content

Add v-model changes to migration guide #143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 13, 2020
1 change: 1 addition & 0 deletions src/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ const sidebar = {
'migration',
'migration/global-api',
'migration/treeshaking',
'migration/v-model',
'migration/functional-components',
'migration/async-components',
'migration/custom-directives'
Expand Down
55 changes: 0 additions & 55 deletions src/guide/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,58 +37,3 @@ It depends on a few factors:
> If I upgrade to Vue 3, will I also have to upgrade Vuex and Vue Router?

[//]: # 'TODO: still need to see where this lands'

## Built-in Directives

### `v-model` API Change

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.

However, 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.

Using v-model in Vue 3
In Vue 3, by detaching the `v-model` from the `value` prop, developers now have the ability to pass arguments to `v-model` which will allow them to create multiple `v-model` bindings on a single component.

```html
<SignupForm v-model:name="”userName”" v-model:email="”userEmail”" />
```

#### Modifiers

In Vue 2.x, hard-coded modifiers such as `.trim` on `v-model` were introduced to provide an intuitive way to solve common scenarios. However,

[//]: # 'TODO: still need to finish, and perhaps add in caveats'

### `v-model.sync` Replaced with `v-model` Argument

In Vue 2, the `.sync` modifier was created in order to offer a shorthand way to create two-way data binding for a prop. For example, in the event we want a child component to update its own title property, we would have done something like this:

**ChildComponent.vue**

```html
this.$emit('onUpdate:title', newTitle)
```

**ParentComponent.vue**

```html
<child-component v-bind:title.sync="pageTitle"></child-component>
```

However, this led to some confusion since two-way data flow is closely tied to the `v-model` directive, whereas `v-bind` is normally used for one-way data flow for props.

#### How to Sync Props in Vue 3

In Vue 3, we no longer need the `.sync` modifier anymore. Similar to how we can listen for changes to a form input value, Vue 3 allows us to perform "two way data binding" on props by allowing you to pass the prop as an argument to `v-model`.

![v-bind anatomy](/images/v-bind-instead-of-sync.png)

Using the example from before, it can now be simplified to:

**ParentComponent.vue**

```html
<child-component v-model:title="pageTitle"></child-component>
```

By passing our prop title to the `v-model` directive, Vue will listen for an `onUpdate:title` event that will be emitted from the child component in order to update the data accordingly.
147 changes: 147 additions & 0 deletions src/guide/migration/v-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Changes to `v-model` on custom components

## Overview

In terms of what has changed, at a high level:

- When used on custom components, `v-model` prop and event default names are changed:
- prop: `value` -> `modelValue`;
- event: `input` -> `update:modelValue`;
- Multiple `v-model` bindings on the same component are possible now;
- **BREAKING:** `v-bind`'s `.sync` modifier and component `model` option are removed and replaced with an argument on `v-model`;
- **NEW:** Added the ability to create custom `v-model` modifiers.

For more information, read on!

## Introduction

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.

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.

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.

## Previous Syntax

In v2, using a `v-model` on a component was an equivalent of passing a `value` prop and emitting an `input` event:

```html
<ChildComponent v-model="pageTitle" />

<!-- would be shorthand for: -->

<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
```

If we wanted to change prop or event names to something different, we would need to add a `model` option to `ChildComponent` component:

```html
<!-- ParentComponent.vue -->

<ChildComponent v-model="pageTitle" />
```

```js
// ChildComponent.vue

export default {
model: {
prop: 'title',
event: 'change'
},
props: {
// this allows using the `value` prop for a different purpose
value: String,
// use `title` as the prop which take the place of `value`
title: {
type: String,
default: 'Default title'
}
}
}
```

So, `v-model` in this case would be a shorthand to

```html
<ChildComponent :title="pageTitle" @change="pageTitle = $event" />
```

### Using `v-bind.sync`

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:

```js
this.$emit('update:title', newValue)
```

Then the parent could listen to that event and update a local data property, if it wants to. For example:

```html
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
```

For convenience, we had a shorthand for this pattern with the .sync modifier:

```html
<ChildComponent :title.sync="pageTitle" />
```

## Current Syntax

In v3 `v-model` on the custom component is an equivalent of passing a `modelValue` prop and emitting an `update:modelValue` event:

```html
<ChildComponent v-model="pageTitle" />

<!-- would be shorthand for: -->

<MyBook :modelValue="pageTitle" @update:modelValue="pageTitle = $event" />
```

### `v-model` arguments

To change a model name, instead of a `model` component option, now we can pass an _argument_ to `v-model`:

```html
<ChildComponent v-model:title="pageTitle" />

<!-- would be shorthand for: -->

<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
```

![v-bind anatomy](/images/v-bind-instead-of-sync.png)

This also serves as a replacement to `.sync` modifier and allows us to have multiple `v-model`s on the custom component.

```html
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />

<!-- would be shorthand for: -->

<ChildComponent
:title="pageTitle"
@update:title="pageTitle = $event"
:content="pageContent"
@update:content="pageContent = $event"
/>
```

### `v-model` modifiers

In addition to v2 hard-coded `v-model` modifiers like `.trim`, now v3 supports custom modifiers:

```html
<ChildComponent v-model.capitalize="pageTitle" />
```

Read more about custom `v-model` modifiers in the [Custom Events](../component-custom-events.html#handling-v-model-modifiers) section.

## Next Steps

For more information on the new `v-model` syntax, see:

- [Using `v-model` on Components](../component-basics.html#using-v-model-on-components)
- [`v-model` arguments](../component-custom-events.html#v-model-arguments)
- [Handling `v-model` modifiers](../component-custom-events.html#v-model-arguments)