Skip to content

Commit

Permalink
fix(v-model): handle mutations of v-model bound array/sets
Browse files Browse the repository at this point in the history
fix #4096
  • Loading branch information
yyx990803 committed Jul 15, 2021
1 parent c23153d commit 2937530
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 6 deletions.
12 changes: 6 additions & 6 deletions packages/runtime-core/src/apiWatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,12 +390,12 @@ export function createPathGetter(ctx: any, path: string) {
}
}

function traverse(value: unknown, seen: Set<unknown> = new Set()) {
if (
!isObject(value) ||
seen.has(value) ||
(value as any)[ReactiveFlags.SKIP]
) {
export function traverse(value: unknown, seen: Set<unknown> = new Set()) {
if (!isObject(value) || (value as any)[ReactiveFlags.SKIP]) {
return value
}
seen = seen || new Set()
if (seen.has(value)) {
return value
}
seen.add(value)
Expand Down
5 changes: 5 additions & 0 deletions packages/runtime-core/src/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
import { ComponentPublicInstance } from './componentPublicInstance'
import { mapCompatDirectiveHook } from './compat/customDirective'
import { pauseTracking, resetTracking } from '@vue/reactivity'
import { traverse } from './apiWatch'

export interface DirectiveBinding<V = any> {
instance: ComponentPublicInstance | null
Expand Down Expand Up @@ -51,6 +52,7 @@ export interface ObjectDirective<T = any, V = any> {
beforeUnmount?: DirectiveHook<T, null, V>
unmounted?: DirectiveHook<T, null, V>
getSSRProps?: SSRDirectiveHook
deep?: boolean
}

export type FunctionDirective<T = any, V = any> = DirectiveHook<T, any, V>
Expand Down Expand Up @@ -101,6 +103,9 @@ export function withDirectives<T extends VNode>(
updated: dir
} as ObjectDirective
}
if (dir.deep) {
traverse(value)
}
bindings.push({
dir,
instance,
Expand Down
4 changes: 4 additions & 0 deletions packages/runtime-dom/src/directives/vModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ export const vModelText: ModelDirective<
}

export const vModelCheckbox: ModelDirective<HTMLInputElement> = {
// #4096 array checkboxes need to be deep traversed
deep: true,
created(el, _, vnode) {
el._assign = getModelAssigner(vnode)
addEventListener(el, 'change', () => {
Expand Down Expand Up @@ -171,6 +173,8 @@ export const vModelRadio: ModelDirective<HTMLInputElement> = {
}

export const vModelSelect: ModelDirective<HTMLSelectElement> = {
// <select multiple> value need to be deep traversed
deep: true,
created(el, { value, modifiers: { number } }, vnode) {
const isSetModel = isSet(value)
addEventListener(el, 'change', () => {
Expand Down

0 comments on commit 2937530

Please sign in to comment.