Vue Unchecking isn't removing data from array? - javascript

I have a function that pushes the networkAudience to the array when the checkbox is checked but when I unchecked it the same network Audience get pushed into the array again. Clicking the networkAudience should be removed when I uncheck the box.
How should I change my function so that a networkAudience is removed if it's unchecked?
new Vue({
el: '#app',
data: {
networkAudience: {}
selected:[]
},
methods: {
netToggle(networkAudience)
{
if(!this.selected.includes(networkAudience))
this.selected.push(networkAudience);
else
this.selected.splice(this.selected.indexOf(networkAudience), 1);
}
}
});
<div v-for="(networkAudience, index) in networkAudiences" : key="index">
<tr>
<input
class="form-check-input"
type="checkbox"
:checked="selected.includes(networkAudience)"
#click="netToggle(networkAudience)"
>
</tr>
</div>
This should only show one object because I unchecked a box but I end up with two objects. The unchecked box duplicates.

If I understood you correctly , try like following snippet:
new Vue({
el: '#app',
data() {
return {
networkAudiences: [{id:1, name:'aaa'}, {id:2, name: 'bbb'}, {id:3, name: 'ccc'}],
networkAudience: {},
selected: []
}
},
methods: {
netToggle(networkAudience) {
if(!this.selected.includes(networkAudience)) {
this.selected.push(networkAudience);
} else {
this.selected.splice(this.selected.indexOf(networkAudience), 1);
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(networkAudience, index) in networkAudiences" :key="index">
<div>
<label :for="networkAudience.id">{{ networkAudience.name }}</label>
<input
class="form-check-input"
type="checkbox"
:id="networkAudience.id"
:value="networkAudiences[index]"
#input="netToggle(networkAudience)"
/>
</div>
</div>
{{selected}}
</div>

Related

Delete updated v-model checkbox property in vuejs

I have a input checkbox tag which I'm trying to delete after it has been updated in my v-model please how can I go about this.
This is my input tag:
<input
v-model="checked"
type="checkbox"
id=""
value="jackets"
>
I get the v-model value property by doing this
{{checked}}
Please how can I add a delete function to my v-model property in which if I click on the delete function the checkbox would be unchecked.
If I understood you correctly try like following snippet (just set your checked property to false):
new Vue({
el: '#demo',
data() {
return {
checked: true,
filters: [{name: 'XXL', state: false}, {name: 'Grey', state: false}]
}
},
methods: {
del() {
this.filters.forEach(f => f.state = false)
},
rem(i) {
this.filters[i].state = false
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div v-for="(filter, i) in filters" :key="i">
{{ filter.name }}
<input
v-model="filter.state"
type="checkbox"
id=""
:value="filter.name"
/>
<button #click="rem(i)">X</button>
</div>
Remove All
<input
type="checkbox"
id=""
#input="del"
/>
</div>

Vue can't check the recently unchecked, checkbox even its binding

I have a list of checkboxes, I want when I click on input 4th all previous boxes being checked and the rest unchecked.
I almost did it, but there is an issue that when I back to the those checked boxes and uncheck one of them, its still okay and the next being unchecked, but when again going forward and check another one from those unchecked the recently unchecked item being still unchecked and not changed.
here is the demo, and I think the GIF will describe my issue better.
Demo https://jsfiddle.net/j5dpkut8/1/
<script src="https://unpkg.com/vue"></script>
<div id="app">
<input type="checkbox" v-model="checked[0]" value="0" #change="printState(0)"> checked 0 <br>
<input type="checkbox" v-model="checked[1]" value="1" #change="printState(1)"> checked 1 <br>
<input type="checkbox" v-model="checked[2]" value="2" #change="printState(2)"> checked 2 <br>
<input type="checkbox" v-model="checked[3]" value="3" #change="printState(3)"> checked 3 <br>
<input type="checkbox" v-model="checked[4]" value="4" #change="printState(4)"> checked 4 <br>
<input type="checkbox" v-model="checked[5]" value="5" #change="printState(5)"> checked 5 <br>
<input type="checkbox" v-model="checked[6]" value="6" #change="printState(6)"> checked 6 <br>
<input type="checkbox" v-model="checked[7]" value="7" #change="printState(7)"> checked 7 <br>
</div>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
checked: [
false,false,false,false,false,false,false,false,
],
},
methods: {
printState(x) {
this.checked = [
false,
false,
false,
false,
false,
false,
false,
false,
],
for (let i = 1; i < this.checked.length; i++) {
if (i <= x) {
this.checked[i] = true;
}
}
console.log(this.checked);
},
}
})
In your code change change handler into click handler and all will be okey.
Or.
new Vue({
el: '#app',
data: {
checked: [
{ state: false },
{ state: false },
{ state: false },
{ state: false },
{ state: false },
{ state: false },
{ state: false },
{ state: false },
],
},
methods: {
printState(x) {
for (let i = 0; i < this.checked.length; i++) {
this.checked[i].state = i <= x ? true : false;
}
},
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<div v-for="(n, index) in checked" :key="index">
<input
type="checkbox"
v-model="n.state"
#click="printState(index)"
>
<span>checked {{ index }} {{ n.state }}</span>
</div>
</div>
As #TigranAbrahamyan mentioned, #click will fix it. But here is a solution in very few lines that also uses v-model and value as intended and lets you easily adjust the number of boxes.
new Vue({
el: "#app",
data: () => ({ num: 10, values: [] }),
methods: {
mark(index) {
this.values = [...Array(index).keys()];
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="index in num" :key="index-1">
<input type="checkbox" v-model="values" :value="index-1" #click="mark(index-1)" />
</div>
</div>

`model` property seems to do nothing

I forked a fiddle with a simple radio button functionality and changed it a bit. It works perfectly, as you can see in this fiddle:
Vue.component('radio-button', {
props: ['id', 'value'],
template: `
<label class="radio">
<input type="radio" :value="id" v-model="radioButtonValue">
<span>{{ id }}</span>
</label>
`,
computed: {
radioButtonValue: {
get: function() {
return this.value;
},
set: function() {
this.$emit("input", this.id);
}
}
}
});
Vue.component('example-form', {
template: `
<div>
<radio-button id="1" v-model="selectedValue"/>
<radio-button id="2" v-model="selectedValue"/>
<radio-button id="3" v-model="selectedValue"/>
<div class="result">
Radio button selection: {{selectedValue}}
</div>
</div>
`,
data: function() {
return {
selectedValue: null
};
}
});
new Vue({
el: '#my-app',
template: `<example-form></example-form>`
});
<script src="https://unpkg.com/vue#2.0.4/dist/vue.js"></script>
<div id="my-app"></div>
However, it only seems to work when the emitted event in the radio-button component is input.
If, for example, I want to use a different value name ("myvar") and a custom event name ("foobar") by utilizing the model property to do so, it doesn't work at all:
Vue.component('radio-button', {
props: ['id', 'myval'],
model: {
prop: 'myval',
event: 'foobar'
},
template: `
<label class="radio">
<input type="radio" :value="id" v-model="radioButtonValue">
<span>{{ id }}</span>
</label>
`,
computed: {
radioButtonValue: {
get: function() {
return this.myval;
},
set: function() {
this.$emit("foobar", this.id);
}
}
}
});
Vue.component('example-form', {
template: `
<div>
<radio-button id="1" v-model="selectedValue"/>
<radio-button id="2" v-model="selectedValue"/>
<radio-button id="3" v-model="selectedValue"/>
<div class="result">
Radio button selection: {{selectedValue}}
</div>
</div>
`,
data: function() {
return {
selectedValue: null
};
}
});
new Vue({
el: '#my-app',
template: `<example-form></example-form>`
});
<script src="https://unpkg.com/vue#2.0.4/dist/vue.js"></script>
<div id="my-app"></div>
What the model property does is it specifies that:
<radio-button id="1" v-model="selectedValue"/>
is "translated" to:
<radio-button id="1" :myvar="selectedValue" #foobar="selectedValue = $event"/>
instead of the default:
<radio-button id="1" :value="selectedValue" #input="selectedValue = $event"/>
is that right?
Am I missing something or is this a bug in Vue?
What you are describing is how v-model works
v-model="anything" is shorthand for :value="anything" #input="anything = $event". So unless you follow that convention of accepting a value prop and emiting an input event, your parent component will not work.
The reason that your first example works is because your radio button component accepts a value prop and you emit an input
So in this case you have two options, follow the convention of v-model in your radio-button component or do something custom and pass down any prop name and emit any event up.

Checkbox click invalid data inside v-for loop

I would like to validate at least one need to check the checkbox.
I'm trying to validate when I clicked on checkbox through the loop.
When I checked one, the output is invalid return false in the first click. When I unchecked return true. But when I checked my sizes array data with vue-dev tools data is valid. I'm trying to find that bugs but I didn't find.
I don't know why.I would like to know that's why? Am I wrong?
new Vue({
el: '#app',
data: {
sizes:[
{id:1,name:'small',ischeck:false,price:0},
{id:2,name:'medium',ischeck:false,price:0},
{id:3,name:'large',ischeck:false,price:0}
],
newval:[]
},
methods: {
checkchanged(){
for(var i=0;i<this.sizes.length;i++){
console.log(this.sizes[i].ischeck);
}
}
}
})
<script src="https://unpkg.com/vue#2.5.17/dist/vue.js"></script>
<div id="app">
<span v-for="size in sizes">
<input type="checkbox" v-model="size.ischeck" :value="size.ischeck"
#click="checkchanged">
<label>{{size.name}}</label>
<input type="text" :disabled="!size.ischeck" v-model="size.price">
</span>
</div>
You could do that using computed property which you call error and hide/show the error message according to that property value:
new Vue({
el: '#app',
data: {
sizes:[
{id:1,name:'small',ischeck:false,price:0},
{id:2,name:'medium',ischeck:false,price:0},
{id:3,name:'large',ischeck:false,price:0}
],
newval:[],
},
methods: {
checkchanged(){
for(var i=0;i<this.sizes.length;i++){
console.log(this.sizes[i].ischeck);
}
}
},
computed:{
error(){
for(var i=0;i<this.sizes.length;i++){
if(this.sizes[i].ischeck) return false;
}
return true;
}
}
})
<script src="https://unpkg.com/vue#2.5.17/dist/vue.js"></script>
<div id="app" style="display :flex;flex-direction: column;">
<div v-for="size in sizes">
<input type="checkbox" v-model="size.ischeck" :value="size.ischeck"
#change="checkchanged">
<label>{{size.name}}</label>
<input type="text" :disabled="!size.ischeck" v-model="size.price">
</div>
<div v-if="error" style="color:red">
there's an error !
</div>
</div>
Finally you don't need to that event #click="checkchanged" you can use #change="checkchanged" instead

Dynamically adding different components in Vue

I want to create a simple form builder with Vue where users click on buttons from a menu to add different form fields to a form. I know that if there was just one type of form field to add, I could do it with something like this (https://jsfiddle.net/u6j1uc3u/32/):
<div id="app">
<form-input v-for="field in fields"></form-input>
<button type="button" v-on:click="addFormElement()">Add Form Element</button>
</div>
<script type="x-template" id="form-input">
<div>
<label>Text</label>
<input type="text" />
</div>
</script>
And:
Vue.component('form-input', {
template: '#form-input'
});
new Vue({
el: '#app',
data: {
fields: [],
count: 0
},
methods: {
addFormElement: function() {
this.fields.push({type: 'text', placeholder: 'Textbox ' + (++this.count)});
}
}
})
But what if there's more than one type of form field (input, file, select, etc...)? I was thinking maybe build a different component for each type, but then how would I show multiple types of components in a single list of form elements?
Could I maybe create a component with children components of different types based on the data in the fields array?
Or is there a better way to go about this situation that I'm missing? I've just started learning Vue, so any help is appreciated!
Ok, so I looked into dynamic elements and managed to pull this together:
Vue.component('form-input', {
template: '#form-input'
});
Vue.component('form-select', {
template: '#form-select'
});
Vue.component('form-textarea', {
template: '#form-textarea'
});
new Vue({
el: '#app',
data: {
fields: [],
count: 0
},
methods: {
addFormElement: function(type) {
this.fields.push({
'type': type,
id: this.count++
});
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.min.js"></script>
<div id="app">
<component v-for="field in fields" v-bind:is="field.type" :key="field.id"></component>
<button type="button" v-on:click="addFormElement('form-input')">Add Textbox</button>
<button type="button" v-on:click="addFormElement('form-select')">Add Select</button>
<button type="button" v-on:click="addFormElement('form-textarea')">Add Textarea</button>
</div>
<script type="x-template" id="form-input">
<div>
<label>Text</label>
<input type="text" />
</div>
</script>
<script type="x-template" id="form-select">
<div>
<label>Select</label>
<select>
<option>Option 1</option>
<option>Option 2</option>
</select>
</div>
</script>
<script type="x-template" id="form-textarea">
<div>
<label>Textarea</label>
<textarea></textarea>
</div>
</script>
So instead of creating a new form-input component for each item in the fields array, I'm creating a new component that is associated with the correct component via the type property of the fields
You can pass the field object as props of your form-input component and make the type dynamic:
Vue.component('form-input', {
template: '#form-input',
props: ['field']
})
new Vue({
el: '#app',
data: {
fields: [],
inputType: '',
count: 0
},
methods: {
addFormElement(val) {
this.fields.push({type: val, placeholder: 'Textbox ' + (++this.count)});
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<h3>Add form element</h3>
<select size="3" v-model='inputType' #click="addFormElement(inputType)">
<option value="text">Text</option>
<option value="checkbox">Checkbox</option>
<option value="radio">Radio</option>
</select>
<p>
<form-input v-for="field in fields" :field="field"></form-input>
</p>
</div>
<template id="form-input">
<div>
<label>{{ field.type }}</label>
<input :type="field.type" />
</div>
</template>
Based on the code from the answer, one could add dynamic content for each one of those form controls as well ( the full concept could be seen from the following site):
Vue.component('form-input', {
template: '#form-input'
, props: ['label','cnt']
});
Vue.component('form-select', {
template: '#form-select'
, props: ['label','cnt']
});
Vue.component('form-textarea', {
template: '#form-textarea'
, props: ['label','cnt']
});
new Vue({
el: '#app',
data: {
fields: [],
count: 0
}
, mounted() {
// fetch those from back-end
this.addFormElement('form-input','lbl', "form-input-content")
this.addFormElement('form-textarea','lbl', "form-textarea-content")
var select_cnt = [
{'value': 1, 'text': 'item-01'},
{'value': 2, 'text': 'item-02'}
]
this.addFormElement('form-select','some-label',select_cnt)
}
, methods: {
addFormElement: function(type,label,cnt) {
this.fields.push({
'type': type
, id: this.count++
, 'label':label
, 'cnt':cnt
});
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.min.js"></script>
<div id="app">
<component v-for="field in fields" v-bind:is="field.type" :key="field.id" :cnt="field.cnt" :label="field.label"></component>
</div>
<script type="x-template" id="form-input">
<div v-on:keyup.tab="this.document.execCommand('selectAll',false,null);">
<label>{{label}}</label>
<input type="text" :value="cnt"/>
</div>
</script>
<script type="x-template" id="form-textarea">
<div v-on:keyup.tab="this.document.execCommand('selectAll',false,null);">
<label>{{label}}</label>
<textarea :value="cnt"></textarea>
</div>
</script>
<script type="x-template" id="form-select">
<div>
<label>Select</label>
<select>
<option v-for="oitem in cnt" :value="oitem.value">{{oitem.text}}</option>
</select>
</div>
<div v-html="cnt"></div>
</script>

Categories