Checkbox click invalid data inside v-for loop - javascript

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

Related

Vue Unchecking isn't removing data from array?

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>

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>

Checkbox validation and rerouting in VUE.js

I am trying to validate the check box and navigate to next link for ex google.com. I found the solution for checkbox validation from the below link
Vue JS - Checkbox validation error on submit from #wolfrevo
new Vue({
el: "#app",
data: {
termsState: false,
validated: false,
nextPageUrl:'www.google.com'
},
computed: {
termsError() {
return this.validated && !this.termsState
}
},
methods: {
handleTermsState() {
this.validated = false
},
handleSubmit() {
this.validated = true
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id='app'>
<label for="terms">
Terms and Privacy Policy
<input type="checkbox" id="terms" name="terms" v-model="termsState" #change="handleTermsState">
{{ termsState }}
</label>
<p style="color: red" class="for-error terms-error" v-if="termsError">You have to agree the terms and privacy condition.</p>
<router-link :to="nextPageUrl">
<div><button type="submit" #click="handleSubmit">Submit</button></div>
</router-link>
</div>
I tried adding router-link, it is redirecting even without validating the checkbox. what is that I am missing?

`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.

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