VueJS checkbox update - javascript

I'm a little wired with VueJS states.
This is my simple app :
new Vue({
el: '#media-app',
data: {
activeTypes: [],
activeCategories: [],
medias: []
},
methods: {
getFilteredData: function () {
// some computing needed
// refresh vue
Vue.set(me, "medias", []);
},
filterMedia: function () {
console.debug(this.activeCategories);
console.debug(this.activeTypes);
this.getFilteredData();
}
}
});
And some HTML stuff:
<input type="checkbox" id="i1" value="i1" class="filter categories" v-model="activeCategories" v-on:click="filterMedia()">
<label for='i1'>My cat 1</label>
</div>
#{{ activeCategories }}
When I check the checkbox, the template displays #{{ activeCategories }} correctly with "i1". But the console.debug(this.activeCategories) displays an empty array. I have to put that debug into an updated method to get the correct value. But if I do that, I cannot call a method which change the data or I'll get into an infinity loop…
So, where should I call my filterMedia function to be able to access updated values from activeCategories ?
Thanks for your help.

Try the onchange event:
<input type="checkbox" id="i1" value="i1" class="filter categories"
v-model="activeCategories" v-on:change="filterMedia()">

Related

Vue select change event firing before I trigger any action

I have a Vue app that seems to fire the change event even before I change the selection, recently tried the #input instead but still the same thing happens(as shown below)
Please note I have tried #change and #input and the event still fires on loading of the controls
Now this was working before I made css changes to scope the component, so that it doesn't effect the surrounding css. But cant fathom why this would make any difference.
Does anyone know why when adding the options tag and contents would make the change event fire?
<div class="form-group" :class="{formError: errors.has('formSection')}">
<label for="formSection">Section*</label>
{{ formModel }}
<select
v-model="formModel.idSection1"
class="form-control"
id="formSection"
name="formSection"
#input="onChangeSectionLevel1">
<option v-for="sectionLevel1 in formModel.sectionLevel1"
v-bind:value="sectionLevel1.value"
v-bind:key="sectionLevel1.id">
{{ sectionLevel1.value }}
</option>
</select>
<span v-if="errors.has('formSection')">This field is required</span>
</div>
As soon as I add in the options tag which loops through the items the onChangeSectionLevel1 function gets called. I thought it might be vee-validate but taken this out and still happens.
methods: {
onChangeSectionLevel1() {
alert("changed");
...
}
}
Update:
I have noticed that if I print out the object that is being bound, I get this which missing the idSection1 item.
{
"idSection2": null,
"idSection3": null,
}
If I then just put a dummy option as below then I can see my 3 data items including the idSection1 that is missing if I loop through with the v-for
<select
v-model="formModel.idSection1"
class="form-control"
id="formSection"
name="formSection"
#change="onChangeSectionLevel1">
<option>Hello World</option>
</select>
The data item still has the idSection1 listed
{
"idSection1": null,
"idSection2": null,
"idSection3": null
}
Many thanks in advance
Not really an answer, but the code above is find and works as expected in js fiddle
https://jsfiddle.net/andrewp37/a4obkhd5/1/
Code:
<div id="app">
<label for="formSection">Section*</label>
{{ formModel }}
<select
v-model="formModel.idSection1"
class="form-control"
id="formSection"
name="formSection"
#change="onChangeSectionLevel1">
<option v-for="sectionLevel1 in formModel.sectionLevel1"
v-bind:value="sectionLevel1.value"
v-bind:key="sectionLevel1.id">
{{ sectionLevel1.value }}
</option>
</select>
</div>
new Vue({
el: "#app",
data: {
formModel: {
idSection1: null,
sectionLevel1: [
{
id: 1,
value: "Section 1"
}
]
}
},
methods: {
onChangeSectionLevel1() {
alert("changed");
}
}
})
I had noticed that with lots of breakpoints added, the model was being replaces after the page was mounted.

On discard changes, checkbox still having same state

I am having a little problem that it's making headaches.
I have a modal where I show some info with checkboxes, the information, comes from an array, and I set the checkbox states from that array, and example of the array:
this.array = [
{scope: "acc", code: "1", alias: "aaa", selected: true, editable: true},
{scope: "acc", code: "2", alias: "bbb", selected: true, editable: true}
]
The thing that I want to do is to play as normal with the checks, but when i click a discardChanges button, the checkboxes, return the state that they were previously.
<div *ngFor="let account of allAccountsList; let i = index;" class="">
<div class="row">
<input (click)="saveCheck(account.code, account.scope)" [(checked)]="account.selected"
type="checkbox" name="genres" value="adventure" id="{{i}}">
<label for="{{i}}" style="font-family: 'SExtralight'; font-size:14px;"></label>
</div>
</div>
Thank you all.
This code:
<div *ngFor="let account of array1; let i = index;">
<input [checked]="account.selected"
type="checkbox"
name="genres"
id="{{i}}">
<label for="{{i}}"
style="font-size:14px;">{{ account.alias }}
</label>
</div>
Does not update the selected property of the underlying array.
This code:
<div *ngFor="let account of array2; let i = index;">
<input [(ngModel)]="account.selected"
type="checkbox"
name="genres"
id="{{i}}">
<label for="{{i}}"
style="font-size:14px;">{{ account.alias }}
</label>
</div>
<div>
Does update the selected property of the underlying array.
Use the first set of code if you want to ensure that the underlying array data is not changed.
But if you do need to track the changes as the user clicks and allow for a discard changes option, use the second set of code. Then in the component, copy the array to keep the original values:
ngOnInit() {
// Save a copy of the original values
this.array2Copy = this.array2.map(e => ({...e}));
console.log(JSON.stringify(this.array2Copy));
}
discardChanges() {
// Copy the original values over the array
this.array2 = this.array2Copy.map(e => ({...e}));
console.log(JSON.stringify(this.array2Copy));
}
I have a stackblitz of this code here:https://stackblitz.com/edit/angular-arraycopy-deborahk

Input-fields as components with updating data on parent

I'm trying to make a set of components for repetitive use. The components I'm looking to create are various form fields like text, checkbox and so on.
I have all the data in data on my parent vue object, and want that to be the one truth also after the user changes values in those fields.
I know how to use props to pass the data to the component, and emits to pass them back up again. However I want to avoid having to write a new "method" in my parent object for every component I add.
<div class="vue-parent">
<vuefield-checkbox :vmodel="someObject.active" label="Some object active" #value-changed="valueChanged"></vuefield-checkbox>
</div>
My component is something like:
Vue.component('vuefield-checkbox',{
props: ['vmodel', 'label'],
data(){
return {
value: this.vmodel
}
},
template:`<div class="form-field form-field-checkbox">
<div class="form-group">
<label>
<input type="checkbox" v-model="value" #change="$emit('value-changed', value)">
{{label}}
</label>
</div>
</div>`
});
I have this Vue object:
var vueObject= new Vue({
el: '.vue-parent',
data:{
someNumber:0,
someBoolean:false,
anotherBoolean: true,
someObject:{
name:'My object',
active:false
},
imageAd: {
}
},
methods: {
valueChange: function (newVal) {
this.carouselAd.autoOrder = newVal;
}
}
});
See this jsfiddle to see example: JsFiddle
The jsfiddle is a working example using a hard-coded method to set one specific value. I'd like to eighter write everything inline where i use the component, or write a generic method to update the parents data. Is this possible?
Minde
You can use v-model on your component.
When using v-model on a component, it will bind to the property value and it will update on input event.
HTML
<div class="vue-parent">
<vuefield-checkbox v-model="someObject.active" label="Some object active"></vuefield-checkbox>
<p>Parents someObject.active: {{someObject.active}}</p>
</div>
Javascript
Vue.component('vuefield-checkbox',{
props: ['value', 'label'],
data(){
return {
innerValue: this.value
}
},
template:`<div class="form-field form-field-checkbox">
<div class="form-group">
<label>
<input type="checkbox" v-model="innerValue" #change="$emit('input', innerValue)">
{{label}}
</label>
</div>
</div>`
});
var vueObject= new Vue({
el: '.vue-parent',
data:{
someNumber:0,
someBoolean:false,
anotherBoolean: true,
someObject:{
name:'My object',
active:false
},
imageAd: {
}
}
});
Example fiddle: https://jsfiddle.net/hqb6ufwr/2/
As an addition to Gudradain answer - v-model field and event can be customized:
From here: https://v2.vuejs.org/v2/guide/components.html#Customizing-Component-v-model
By default, v-model on a component uses value as the prop and input as
the event, but some input types such as checkboxes and radio buttons
may want to use the value prop for a different purpose. Using the
model option can avoid the conflict in such cases:
Vue.component('my-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean,
// this allows using the `value` prop for a different purpose
value: String
},
// ...
})
<my-checkbox v-model="foo" value="some value"></my-checkbox>
The above will be equivalent to:
<my-checkbox
:checked="foo"
#change="val => { foo = val }"
value="some value">
</my-checkbox>

Vue.js how to delete component v-for values

I am learning Vue, so I created radio button component, but I am struggling with how can one delete these values. My current solution deletes actual values, but selection is still displayed.
This is the component
<template id="fradio">
<div>
<div class="field is-horizontal">
<div class="field-label" v-bind:class = "{ 'required' : required }">
<label
class = "label"
>{{label}}
</label>
</div>
<div class="field-body">
<div>
<div class="field is-narrow">
<p class="control" v-for="val in values">
<label class = "radio">
<input
type="radio"
v-bind:name = "name"
v-bind:id = "name"
#click = "updateValue(val)"
>
<span>{{val[valueLabel]}}</span>
<span v-if="!valueLabel">{{val}}</span>
</label>
<label class="radio">
<button class="delete is-small" #click="removeValue"></button>
</label>
<slot></slot>
</p>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
label: {
type: String,
required: true,
},
inputclass: {
type: String,
},
required: {
type: Boolean,
default: false,
},
valueLabel:{
type: String,
},
returnValue:{
type: String,
},
values:{},
name:'',
},
data() {
return {
};
},
methods: {
updateValue: function (value) {
var selectedValue;
(!this.returnValue) ? selectedValue = value : selectedValue = value[this.returnValue];
this.$emit('input', selectedValue)
},
removeValue: function() {
this.$emit('input',null);
},
},
}
</script>
It should be easy, but I need someone to point out the obvious...
Update:
I just realized that you may be more focused on the data not dynamically updating, which means that your issue might be that the data in the parent component is not being updated. Most of your data is being passed down as props, so I'd need to see how the event is being fired in the parent component in order to help diagnose what's wrong. Based on the code you provided, it looks like your removeValue() function is emitting an event but I don't see any code that actually removes the value.
I would check the parent component to make sure that it is removing the child component and that should fix your problem!
Initial Answer:
Generally, when removing an item from a v-for list, you need to know the index of the item and use the Array.splice in order to modify the list to remove it.
Here's a generic example off the top of my head.
<template>
<ul>
<li v-for="(fruit, index) in fruits"
#click="removeItem(index)">
{{ fruit }}
</li>
</ul>
</template>
<script>
export default {
data() {
return {
fruits: ['Apple', 'Banana', 'Clementines']
}
},
methods: {
removeItem(index) {
this.fruits.splice(index, 1)
}
}
}
</script>
Let me know if you have any questions!

Vue JS, checkboxes and computed properties

I am having some problems using vue, checkboxes and computed properties.
I made a very small example showing my problem: https://jsfiddle.net/El_Matella/s2u8syb3/1/
Here is the HTML code:
<div id="general">
Variable:
<input type="checkbox" v-model="variable">
Computed:
<input type="checkbox" v-model="computed()">
</div>
And the Vue code:
new Vue({
el: '#general',
data: {
variable: true
},
compute: {
computed: function() {
return true;
}
}
})
The problem is, I can't make the v-model="computed" work, it seems that Vue doesn't allow such things.
So my question is, how could I use the benefits of the computed data and apply it to checkboxes?
Here is an other jsfiddle showing the same problem, but with more code, I was trying to use computed properties to build a "selected" products array variable: https://jsfiddle.net/El_Matella/s2u8syb3/
Thank you for your answers and have a nice day!
Computed properties are basically JavaScript getters and setters, they are used like regular properties.
You can use a computed setter to set the value (currently, you only have a getter). You will need to have a data or props property in which you can save the changes of the model though, because getters and setters don't have an inherent state.
new Vue({
el: '#general',
data: {
variable: true,
cmpVariable: true,
},
computed: { // "computed" instead of "compute"
cmp: {
get: function() {
return this.$data.cmpVariable;
},
set: function(val) {
this.$data.cmpVariable = val;
},
}
}
});
Also, you don't need to call the computed with brackets (as it behaves like a regular property):
<div id="general">
Variable:
<input type="checkbox" v-model="variable">
Computed:
<input type="checkbox" v-model="cmp">
</div>
You miss-spelled computed. Here Computed Properties
I guess you want to check an item in Product list,
So it can be displayed in the selected list.
And you also want to check it off from both the lists.
Thus you don't need a computed property.
For check boxes, you can easily change the selected set by referring to it with v-model and set value for what you want to put in the set.
In your case, that's the product.id.
You may want to save the object itself in the selectedProducts list,
but I highly recommend you not to do that.
In some case, it will cause unexpected results as objects are mutable.
So it will work if it is written this way.
new Vue({
el: '#general',
data: {
products: [{
id: 1
}, {
id: 2
}],
selectedProducts: []
}
})
<script src="//cdn.bootcss.com/vue/1.0.13/vue.min.js"></script>
<h1>Hello</h1>
<div id="general">
<h2>Products</h2>
<ul>
<li v-for="product in products">
<input v-model="selectedProducts" value="{{product.id}}" type="checkbox">{{ product.id }}
</li>
</ul>
<h2>Selected Products</h2>
<ul>
<li v-for="p in selectedProducts">
<input v-model="selectedProducts" value="{{p}}" type="checkbox">{{ p }}
</li>
</ul>
</div>

Categories

Resources