Skip to content

Commit 782c3e6

Browse files
fixes T1277897: fixed v-model binding in view 3 on checkbox (#29312)
Co-authored-by: sergey-kras <[email protected]>
1 parent 56e944a commit 782c3e6

File tree

4 files changed

+85
-7
lines changed

4 files changed

+85
-7
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<template>
2+
<example-block title="v-model">
3+
DX with value:
4+
<br>
5+
<dx-check-box v-model="dxCheckBoxValue" />
6+
<br>
7+
<div>checkBoxValue: {{ dxCheckBoxValue ? '🟢' : '🔴' }}</div>
8+
<br>
9+
-------------
10+
<br>
11+
Native checkbox with modelValue:
12+
<br>
13+
<input type="checkbox" v-model="checkBoxValue2" />
14+
<br>
15+
<div>checkBoxValue: {{ checkBoxValue2 ? '🟢' : '🔴' }}</div>
16+
<br>
17+
</example-block>
18+
</template>
19+
20+
<script>
21+
import { ref, watch } from "vue";
22+
import ExampleBlock from "./example-block";
23+
import { DxCheckBox } from "devextreme-vue/check-box";
24+
25+
const checkBoxValue2 = ref(false);
26+
27+
watch(checkBoxValue2, (newValue) => console.log("checkBoxValue2 changed:", newValue));
28+
29+
export default {
30+
components: {
31+
ExampleBlock,
32+
DxCheckBox,
33+
},
34+
data() {
35+
return {
36+
dxCheckBoxValue: false,
37+
checkBoxValue2,
38+
};
39+
},
40+
};
41+
</script>

apps/vue/components/examples.vue

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
<text-box-example/>
2929
<br/>
3030
<validator-example/>
31+
<br/>
32+
<check-box-example/>
33+
<br/>
3134
</template>
3235

3336
<script>
@@ -46,7 +49,8 @@ import ScrollViewExample from "./scroll-view-example";
4649
import TabPanelExample from "./tab-panel-example";
4750
import TextBoxExample from "./text-box-example";
4851
import ValidatorExample from "./validation-example";
49-
52+
import CheckBoxExample from "./check-box-example";
53+
5054
export default {
5155
components: {
5256
AccessingInstanceExample,
@@ -63,7 +67,8 @@ export default {
6367
ScrollViewExample,
6468
TabPanelExample,
6569
TextBoxExample,
66-
ValidatorExample
70+
ValidatorExample,
71+
CheckBoxExample
6772
}
6873
};
6974
</script>

packages/devextreme-vue/src/core/__tests__/configuration.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ComponentPublicInstance, reactive } from 'vue';
2+
import { VMODEL_NAME } from '../vue-helper';
23
import Configuration, {
34
bindOptionWatchers,
45
ExpectedChild,
@@ -644,4 +645,35 @@ describe('onOptionChanged', () => {
644645

645646
expect(emitStubRoot).toHaveBeenCalledTimes(0);
646647
});
648+
649+
it('should use v-model event name and mutate innerChanges with VMODEL_NAME when option is "value" and v-model is active', () => {
650+
const innerChanges = {};
651+
const config = new Configuration(jest.fn(), null, {});
652+
const emitStub = jest.fn();
653+
const component = {
654+
$emit: emitStub,
655+
$props: { value: false, [VMODEL_NAME]: false },
656+
$options: {
657+
props: { value: false, [VMODEL_NAME]: false },
658+
model: true,
659+
},
660+
$: {
661+
vnode: {
662+
props: { value: false, [VMODEL_NAME]: false },
663+
},
664+
},
665+
};
666+
setEmitOptionChangedFunc(config, component as unknown as ComponentPublicInstance, innerChanges);
667+
668+
config.onOptionChanged({
669+
fullName: 'value',
670+
value: true,
671+
previousValue: false,
672+
component: null,
673+
});
674+
675+
expect(emitStub).toHaveBeenCalledTimes(1);
676+
expect(emitStub).toHaveBeenCalledWith(`update:${VMODEL_NAME}`, true);
677+
expect(innerChanges[VMODEL_NAME]).toBe(true);
678+
});
647679
});

packages/devextreme-vue/src/core/configuration.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -306,12 +306,12 @@ function setEmitOptionChangedFunc(
306306
config.emitOptionChanged = (name: string, value: string) => {
307307
const props = vueInstance.$props;
308308
const vnode = vueInstance?.$?.vnode;
309-
if (hasProp(vueInstance, name) && !isEqual(value, props[name]) && vueInstance.$emit) {
310-
innerChanges[name] = toRaw(value);
311-
const eventName = name === 'value' && hasVModelValue(vueInstance.$options, props, vnode)
312-
? `update:${VMODEL_NAME}`
313-
: `update:${name}`;
314309

310+
const propsName = name === 'value' && hasVModelValue(vueInstance.$options, props, vnode) ? VMODEL_NAME : name;
311+
const eventName = `update:${propsName}`;
312+
313+
if (hasProp(vueInstance, name) && !isEqual(value, props[propsName]) && vueInstance.$emit) {
314+
innerChanges[propsName] = toRaw(value);
315315
vueInstance.$emit(eventName, value);
316316
}
317317
};

0 commit comments

Comments
 (0)