vue: Checkbox doesn't check with binding checked attribute

Version

2.3.3

Reproduction link

http://jsfiddle.net/yMv7y/2617/

Steps to reproduce

Instead of using v-model on the native checkbox, simply use :checked="computedProp" to manage the checkbox’s checked state and block UI-checking (mouse-click, and tab-space-ing) by doing e.preventDefault() on click.

What is expected?

For the checkbox to check.

What is actually happening?

The checkbox is not checking, despite that the computed property is evaluating to true.


I don’t want to use v-model because, from what I understand, v-model is short for something like :checked="foo" and @change="val => { foo = val }" (the exact logic found here), and since I am making a minimal Checkbox component only to wrap the native checkbox with some elaborate CSS, I’d like to refrain from having to maintain any “data” props, and instead of the event handler v-model comes with, I’d like to simply hoist the event up.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 8
  • Comments: 17 (5 by maintainers)

Most upvoted comments

You never set this.checked to a value. So the checkbox won’t update. Besides, do yourself a favor and use v-model. It’s much easier, even for wrapped components. That doesn’t stop the component from implementing a v-model interface itself or customizing the model.

This is an implementation that works: http://jsfiddle.net/t08v9ny6/3/

This is still an issue for me, I still don’t see why doing something along the lines of <input type="checkbox" :checked="someBooleanValue"> wouldn’t work properly? I don’t want to be using v-model since I also want the boolean toggle to occur programatically when clicking on the parent element of the input element.

Looks like the behavior is caused by the e.preventDefault() call. My assumption is that this is because Vue’s DOM update kicks in via a microtask before the browser checks for preventDefault behavior - the browser resets the checkbox state when it sees that the event default behavior has been prevented, overwriting the DOM changes made by Vue.

In Firefox this works properly, so I think this is a Chrome/Webkit-only behavior.

I’m not sure why you need e.preventDefault() here, but if you really need it, you can wrap the $emit calls in a setTimeout to get around this: http://jsfiddle.net/yMv7y/2621/

This is very confusing, how do we use binding on a checkbox? v-model doesn’t work on the input element from within a child components for some reason??

Same happens on <input type="radio" /> elements.

<input type="checkbox" :checked="checked" :data-wug="checked"/> renders to <input type="checkbox" data-wug="true"/> and not <input type="checkbox" checked data-wug="true"/> as expected.

@yyx990803 - thank you for that example! I have had a lot of trouble with this in Vuex - e.preventDefault() throws the whole thing out of whack.

What I was going for was only actually toggling the checkbox if a Vuex action (and mutation) were successful. So basically, even if a user checked a checkbox - that doesn’t mean I want it to go to a checked state - I just want it to keep following its computed property it was already set to using :checked. And because using v-model in Vuex isn’t a good idea, I found that the UI was getting toggled even though I hadn’t committed a mutation. I found this strange. In further research, I actually found there wasn’t a good answer to this question. I couldn’t believe it - as I believed this to be a common pattern - not wanting a checkbox to toggle until some action is complete - that way you can deal with an error and not end up toggling the checkbox - say, for like a user’s preferences page.

Nothing worked until doing something like your setTimeout example. Thank you, and thank you @hirokiosame for asking this question.