Skip to content

Commit

Permalink
feat: resolve v-model on checkbox element
Browse files Browse the repository at this point in the history
  • Loading branch information
ktsn committed May 12, 2018
1 parent 640a9eb commit f83742f
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 3 deletions.
6 changes: 5 additions & 1 deletion src/view/components/Node.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ export default Vue.extend({
computed: {
vnodeData(): VNodeData {
const { data: node, scope, selectable } = this
const data = convertToVNodeData(node.startTag.attributes, scope)
const data = convertToVNodeData(
node.name,
node.startTag.attributes,
scope
)
if (selectable) {
// The vnode may be a native element or ContainerVueComponent,
Expand Down
28 changes: 27 additions & 1 deletion src/view/rendering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ function parseStyleText(cssText: string): Record<string, string> {
}

export function convertToVNodeData(
tag: string,
attrs: (Attribute | Directive)[],
scope: Record<string, DefaultValue>
): VNodeData {
Expand Down Expand Up @@ -240,7 +241,7 @@ export function convertToVNodeData(
acc.attrs![attr.argument] = value
}
} else if (attr.name === 'model') {
acc.attrs!.value = value
resolveVModel(acc, tag, attrs, value)
} else if (attr.name === 'text') {
acc.domProps!.textContent = value
} else if (attr.name === 'html') {
Expand All @@ -264,6 +265,31 @@ export function convertToVNodeData(
}, initial)
}

function resolveVModel(
data: VNodeData,
tag: string,
attrs: (Attribute | Directive)[],
value: any
): void {
if (tag === 'input') {
const type = attrs.find(a => !a.directive && a.name === 'type')
if (type) {
if (type.value === 'checkbox') {
if (typeof value === 'boolean') {
data.domProps!.checked = value
} else if (Array.isArray(value)) {
const valueAttr = attrs.find(a => !a.directive && a.name === 'value')
if (valueAttr) {
data.domProps!.checked = value.indexOf(valueAttr.value) >= 0
}
}
return
}
}
}
data.attrs!.value = value
}

function isValidAttributeName(name: string): boolean {
return validateName(name).success
}
53 changes: 52 additions & 1 deletion test/view/VueComponent/model.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createTemplate, render, h, d } from '../../helpers/template'
import { createTemplate, render, h, d, a } from '../../helpers/template'

describe('VueComponent v-model', () => {
it('should bind a value with v-model', () => {
Expand All @@ -22,4 +22,55 @@ describe('VueComponent v-model', () => {
const input = wrapper.find('input').element as HTMLInputElement
expect(input.value).toBe('message')
})

it('resolves checkbox v-model', () => {
// prettier-ignore
const template = createTemplate([
h('input', [a('type', 'checkbox'), d('model', 'checked')], [])
])

const wrapper = render(
template,
[],
[
{
name: 'checked',
default: true
}
]
)

const checkbox = wrapper.find('input').element as HTMLInputElement
expect(checkbox.checked).toBe(true)
})

it('resolves multiple checkbox v-model', () => {
// prettier-ignore
const template = createTemplate([
h('div', [], [
h('input', [a('type', 'checkbox'), a('value', 'foo'), d('model', 'list')], []),
h('input', [a('type', 'checkbox'), a('value', 'bar'), d('model', 'list')], []),
h('input', [a('type', 'checkbox'), a('value', 'baz'), d('model', 'list')], []),
])
])

const wrapper = render(
template,
[],
[
{
name: 'list',
default: ['foo', 'baz']
}
]
)

const foo = wrapper.find('input[value=foo]').element as HTMLInputElement
const bar = wrapper.find('input[value=bar]').element as HTMLInputElement
const baz = wrapper.find('input[value=baz]').element as HTMLInputElement

expect(foo.checked).toBe(true)
expect(bar.checked).toBe(false)
expect(baz.checked).toBe(true)
})
})

0 comments on commit f83742f

Please sign in to comment.