2.3.3
http://jsfiddle.net/yMv7y/2617/
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
.
For the checkbox to check.
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.
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/
Thanks for looking into this @Nirazul
this.checked
is a prop, so it doesn't need to be declared but rather passed in (which I do in the Jsfiddle). The input element's checked
attribute is evaluated with the expression this.checked === this.value
where this
is the vm
--the computed property isChecked
in the Jsfiddle-- so it should update.
As I've said, the reason why I would prefer to avoid v-model
is so that the component doesn't need to maintain a state -- which you do in your example by using data()
. In your example, if a variable is bound to the prop checked
, this.val
doesn't update when the parent mutates the value because this.val
is a new property created per instance, reflecting the state of the component.
Functionally, what I need can be achieved by using computed property which bubbles the change
event up on set
and returns the prop value on get
. However, this is not the point I'm making. I'm addressing what _seems_ to be a Vue bug with the input(type=checkbox)
element so it could be further investigated.
Then value
is never defined. Because you're setting the prop for the v-model
binding to checked
.
But in any case, there's a subtle difference between HTML attributes and props. But I'm not skilled enough to explain, why the checked binding wouldn't work. I'll leave this to the library authors ¯_(ツ)_/¯
@Nirazul
value
is also a prop; it's being passed in here (it's in the HTML slot): <o-checkbox v-model="testVal" :value="true">Label</o-checkbox>
Aw don't sell your self short! Thanks for looking into it nonetheless.
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/
@yyx990803
Thanks for looking into it! That's awesome -- I didn't think to see if it was a browser issue.
I use e.preventDefault()
to block the checkbox from checking _just because it was clicked_ and also to ensure that the single source of truth of what the checkbox is reflecting is within the View model rather than the DOM; I needed the checked
state of the input to strictly reflect the data of the View.
@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.
<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.
@GufNZ <input type="checkbox" :checked="checked" :data-wug="checked"/>
is trying to call a function named checked()
, that's why it doesn't render anything. If you want it to output a string checked
, use single quotes:
<input type="checkbox" :checked="'checked'" :data-wug="checked"/>
@dsignr See above; checked
is a source of a boolean value, in this case true
so the checkbox should still have that attribute set, and does not. Or at least, did not, at the time of writing - I haven't checked this in a while.
" 'checked' " => " checked "
For what it's worth:
<input
type="checkbox"
:checked="justTesting"
>
Does work with a justTesting computed value giving 'true'.
justTesting(){
return true
}
In general computers do mess things up when things are named the same. In this case the attribute 'checked' and the computed value 'checked'.
[still looking for a clear example on using checkboxes in combination with vuex]
Same happens on <input type="radio" />
elements.
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??
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.
Related to https://github.com/vuejs/vue/issues/3523
Instead of setting input field checked property to "checked". we have to push value in the model. This will automatically mark the corresponding checkbox as checked.
HTML
<li class="list-group-item" v-for="home in home_data">
<input v-model="homes" :value="home.id" type="checkbox" @click="home.visible=!home.visible" /> {{home.name}}
</li>
Data
"home": [ { "id": 5, "staff_id": 13, "home_id": 8, "created_at": "2020-09-13T13:24:52.000000Z", "updated_at": "2020-09-13T13:24:52.000000Z" }, { "id": 6, "staff_id": 13, "home_id": 6, "created_at": "2020-09-13T13:24:52.000000Z", "updated_at": "2020-09-13T13:24:52.000000Z" } ] }
Function where we are putting data into our model.
this.form = this.edit_data = row;
row.home.forEach((item, index)=> {
console.log(item);
this.assigned_home.push(item.home_id);
this.homes.push(item.home_id);
});
Most helpful comment
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 forpreventDefault
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 asetTimeout
to get around this: http://jsfiddle.net/yMv7y/2621/