How can I correctly set a checkbox as checked using an array of objects - vue.js

The value(s) are being stored correctly—the v-model is correct, I'm just having trouble getting the checkboxes to be checked or not.
Here is my template:
<input type="checkbox"
v-for="thing in things"
:value="thing.id"
v-model="$v.thing.activities.$model"
:checked="$v.thing.activities.$model.some((el) => el.id === thing.id)"
/>
I am using NestJs to handle saving my data. There is a many:many relationship, so the system returning the entire object.
Here is what my v-model looks like. It's an array of objects:
[
0:Object
createdAt:""
description:"This is what thing is."
id:"07347f64-..."
name:"Thing"
updatedAt:""
]
When I click on a checkbox, I can see that the v-model is updated properly with the new id which is great.
I know it's working properly, when I do this on my template to test, it renders true or false as expected:
{{ $v.thing.activities.$model.some((el) => el.id === thing.id) }} // true
I see in the vue docs that v-model will take precedence over :checked, but since my v-model is an array of objects, I'm not sure how to set the checked property of the checkbox.
I've also tried pulling the current loop value and creating a temporary array push/splice values out to get the checkbox to render properly in a created hook. No luck there either. I think everything needs to come from the v-model, but I'm at a loss.
How can I correctly show the checkbox as checked?

Related

Multiple VueSelect

I am obtaining from an API the data to fill a v-select type component, the component is filled correctly and I also obtain the options that the user already had assigned (multiple)
And the v-select component are filled correctly
But when i try to add another option occurs the next
Here is the Source Code
<validation-provider
#default="validationContext"
name="skill"
>
<b-form-group
label="Skills"
label-for="skill_id"
:state="getValidationState(validationContext)"
>
<v-select
v-model="itemData.skills"
:dir="$store.state.appConfig.isRTL ? 'rtl' : 'ltr'"
multiple
:options="skillOptions"
:clearable="false"
:reduce="(val) => val.value"
input-id="skill_id"
/>
<b-form-invalid-feedback
:state="getValidationState(validationContext)"
>
{{ validationContext.errors[0] }}
</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
Here i have the array of objects, with multiple elements
itemEdit.value.skills
Then map to get a reduced array with only the value and label
I have probed using only the label without value and the result is the same
const openEdit = item => {
isSidebarActive.value = true
itemEdit.value = item
itemEdit.value.skills = item.skills.map(skill => ({
value: skill.id,
label: skill.skill,
}))
isAdd.value = false
}
Everything apparently goes right, the v-model match correctly with the available options, the problem comes when the user interact with the vSelect to add another item, the already selected items disappear
Thanks in advance
Based on this page o the Vue Select Documentation, the reduce prop is usually meant for use with a label prop, and is only needed if you provide an object to v-select.
I suspect you are providing an array of primitives in your v-model (ie itemData.skills is an array of strings) instead of an array of objects. If it is an array of objects instead, then I suspect you either don't have a [label] key on the object (the default that label is set to), or you don't have a [value] key (what you are trying to return with your reduce prop).
Ideally, you would give us an example of your data coming in for us to be able to help you better.
thanks for listen, the problem was solved removing:
:reduce="(val) => val.value"
From
<v-select
v-model="itemData.skills"
:dir="$store.state.appConfig.isRTL ? 'rtl' : 'ltr'"
multiple
:options="skillOptions"
:clearable="false"
:reduce="(val) => val.value"
input-id="skill_id"
/>

By default Checked checkbox using v-model

Hi Guys I'm Newbie at VueJS,
Anyone who can help me about on getting default checked at my checkbox list
I'm using v-model so the checked won't work
Any idea or suggestion?
You bind the input to a truthy value using the v-model directive
<input type="checkbox" v-model="selected">
In your component data (Updated based on #Phil s comment)
data () {
return {
selected: true, // True of false, or other truthy value depending on needs
}
}
Then, depending on the value on selected your input will be checked/unchecked.
Note - in the documents it is stated that
v-model will ignore the initial value, checked, or selected attributes
found on any form elements. It will always treat the Vue instance data
as the source of truth. You should declare the initial value on the
JavaScript side, inside the data option of your component.
Read more at https://v2.vuejs.org/v2/guide/components-custom-events.html#Binding-Native-Events-to-Components

Changing value of outer variable used in props after emitted listener from component disables v-model listener effects in Vue.js

Considering following HTML code:
<div id="app">
<comp :is_checked="is_checked" v-on:ch="function(x){is_checked_2=x}"></comp>
<p>{{ is_checked_2 }}</p>
</div>
<script src="app.js"></script>
and app.js:
var tm = `<div>
<input type="checkbox" v-model="is_checked"
v-on:change="$emit('ch',is_checked)"
>{{ is_checked }}
</div>`
Vue.component('comp', {
template: tm,
props: ["is_checked"]
})
new Vue({
el: "#app",
data: function() {
return {
is_checked: null,
is_checked_2: null
};
}
});
If we replace is_checked_2=x by console.log(x) in v-on:ch="function(x){...}, everything works correct and v-model is changing is_checked when input checkbox value changes.
Also if we don't send the value of variable by props and define it locally in component, everything works correct.
It seems that changing the parent Vue's object variable is
regenerating the whole HTML of component where the value of variable
is sent by props and the variable is reset there immediately after
firing the event inside template. It is causing that functions
triggered by events don't change component's variables.
Is it a bug in Vue.js?
To make it more clear, the behavior is following: changing whatever Vue parent value that is not bound and however related to the component (no props, no slots) results at resetting all values in the component that are bound by props. Following only occurs if we reactivelly write to parent/main HTML using modified parent variable, we can achieve that by placing {{ .... }} there. This seems to be the bug.
Example: Vue has variables a and b. We place {{ a }} to the main code. The value of variable b is sent by props to component and matched to variable c. With the time we are changing that value of variable c inside the component. In one moment we decide to change value of a and it results by "forgetting" current state of c and it is reset to initial state by invoked props.
To summarize: the bug itself gets stuck that props should be reactivelly invoked only if corresponding parent variable is changed and not if whatever parent variable changes and at the same time they modify HTML code.
This issue doesn't have nothing to do with event listeners neither events, because it is possible to replicate it without using them.
Conclusion:
{{ is_checked_2 }} or {{ '',is_checked_2 }} or {{ '',console.log(is_checked_2) }} after changing value of is_checked_2 is causing rerendering the whole top Vue component having is_checked as variable and it is resetting child component variable, because it has the same name. The solution is never using the same name for child and parent component variables bound by props. This is issue of Vue/props architecture how it was designed.
I don't think it's a bug.
You're most likely running into a race condition where your change event gets executed before or in place of the internally attached one (hence the seemingly nullified data binding).
Because v-model is essentially just a syntactic sugar for updating data on user input events. Quoting the docs:
v-model internally uses different properties and emits different events for different input elements:
text and textarea elements use value property and input event;
checkboxes and radiobuttons use checked property and change event;
select fields use value as a prop and change as an event.
You might also want to see "Customizing Component v-model".

VueJs 2 - Force Checkbox DOM value to respect data value

I cannot for the life of me figure this out.
Fiddle at: https://jsfiddle.net/s8xvkt10/
I want
User clicks checkbox
Then based on separate conditions
Checkbox calculatedCheckedValue returns a data property /v-model of true/false
And the checked state reflects the calculatedCheckedValue
I can get:
The calculatedCheckedValue calculates and interpolates properly
But I fail at:
Having the :checked attribute render the calculatedCheckedValue properly in the DOM
e.g. If a false checkbox is clicked and the calculatedCheckedValue still returns false, the checkbox toggles onscreen between checked and unchecked
I’ve tried:
Using a v-model with a custom set that does the calculation and sets the local state which the custom get returns
Imitating a v-model using #change.prevent.stop="updateCalculatedValue" and :checked="calculatedValue"
Assuming the #change happens after the #click (which i think is wrong) and using #click.prevent.stop="updateCalculatedValue" and :checked="calculatedValue"
The model is working and rendering the calculated value as string in a DOM span,
but the checked value doesn't seem to respect the model value
Can someone please help me out?
I've solved the problem at: https://jsfiddle.net/pc7y2kwg/2/
As far as I can tell, the click event is triggered even by keyboard events (src)
And happens before the #change or #input events (src)
So you can click.prevent the event, but you need to either prevent it selectively or retrigger the event after the calculation.
//HTML Template
<input :checked="calculatedValue5" #click="correctAnswer" type="checkbox">
//VUE component
data() {
return {
calculatedValue5: false,
};
},
methods: {
correctAnswer(e){
const newDomValue = e.target.checked;
this.calculatedValue5 = this._calculateNewValue(newDomValue);
if(this.calculatedValue5 !== newDomValue){
e.preventDefault();
}
}
}
I think this is preventing checkbox value from updating before the data value, which seems to break the reactivity. I'm not sure the technical reason why, but the demo does work

Vue.js prevent re-render?

I have a template in Vue.js that looks like this:
<div class="filter">
<div class="checkbox" v-for="(value, index) in range" :key="index">
<span class="hotels">{{ count(index) }}</span>
</div><!-- /.checkbox -->
</div><<!-- /.filter -->
The count method is important here. It triggers twice and also seems to be the cause of the second trigger and re-render.
This is my method:
count(value) {
console.log('count');
// Get the filtered AJAX data.
let hotels = this.allHotels;
const filters = Object.entries(this.filters);
for (let i = 0; i < filters.length; i += 1) {
// Get the Object from the array(index 0 being the name).
const filter = filters[i][1];
// Break the v-model reference by creating a shallow copy.
const values = filter.values.slice(0);
// Merge any selected checkbox values with the one we are currently iterating.
if (!values.includes(value)) values.push(Number(value));
// Check if the current filter has selected checkboxes and filter if it does.
hotels = filter.function(hotels, values);
}
return hotels.length;
}
Whenever I everything except the console.log() it works fine. Whenever I leave in the rest of the code the entire template seems to re-trigger. This seems strange because I am leaving the data in the template and the computed properties that the template relies on alone.
Is there any way to debug what is causing the second re-render?
Entire component:
https://gist.github.com/stephan-v/a5fd0b6bae854276666536da445bbf86
Edit
My components count function has a computed property in it called allHotels. This property is being set as a prop.
On the very first console.log it seems empty and then straight away it will get set causing the re-render. I was hoping that because this prop is coming from the backend it would take it as the initial value but this is not the case.
Is there anything to overcome this and prevent a re-render? There is no need for a re-render if Vue would take the prop data from the backend as initial data straight away.
Hopefully it is clear what I mean by this.
Replication:
Somehow I can't seem to replicate this, I would expect this to also work like my code and show an empty title on the first pass with a console.log:
https://jsfiddle.net/cckLd9te/123/
Perhaps because my prop data that I am passing into my component is a pretty big json_encoded block it takes time for Vue.js to interpret the data?