v-model is not working on dynamic radio buttons, vue js - vue.js

var vue = new Vue({
el: '#app',
data: function (){
return {
categories: null,
foodItems: null,
selectedCategoryId: null
}
},
mounted: function() {
axios
.get('#Url.Action("GetCategories", "Home", new { area="Canteen" })')
.then(response => (this.categories = response.data))
}
});
<span>selected: {{ selectedCategoryId }}</span>
<div class="box box-default">
<div class="box-header with-border">
<div class="text-center text-uppercase"><b>Select</b></div>
</div>
<div class="box-body">
<div class="btn-group-vertical btn-block btn-group-toggle" data-toggle="buttons">
<label v-for="(category, index) in categories" class="btn btn-default active">
<input :id="'option-' + category.id" :value="category.id" type="radio" name="categories" autocomplete="off" v-model="selectedCategoryId" />{{ category.name }}
</label>
</div>
</div>
</div>

Here is working example
var vue = new Vue({
el: '#app',
data: function (){
return {
categories: null,
foodItems: null,
selectedCategoryId: null,
isdata:false
}
},
mounted: function() {
console.log("mounted");
var vm = this;
setTimeout(function(){
vm.categories = [
{id:1,name:'test1'},
{id:2,name:'test2'},
{id:3,name:'test3'}
];
vm.isdata = true;
}, 2000);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<span>selected: {{ selectedCategoryId }}</span>
<div class="box box-default">
<div class="box-header with-border">
<div v-show="!isdata">Loading....</div>
<div v-show="isdata" class="text-center text-uppercase"><b>Select</b></div>
</div>
<div class="box-body">
<div class="btn-group-vertical btn-block btn-group-toggle" data-toggle="buttons">
<label v-for="(category, index) in categories" class="btn btn-default active">
<input :id="'option-' + category.id" :value="category.id" type="radio" name="categories" autocomplete="off" v-model="selectedCategoryId" />{{ category.name }}
</label>
</div>
</div>
</div>
</div>

Related

How to get Vue.js to to dynamically add forms with django formset

I have been struggling trying to get Vue.js to dynamically create the form while updating the ids of the form elements. I am new to Vue.js.
I have tried to have each form as a vue component, but I can't seem to update the ids, or they all seem to have the same id when inspecting with vue dev tools.
I have also tried to nest vue instances, then I am able to get the id's to be correct but then the other functionality doesn't work.
html
<body class="bg-dark">
<!--style="background-color:Black;"-->
<div class="container-fluid p-4 bg-dark text-white" style="margin-top:74px">
<div class="row">
<div class="col-md-3"></div>
<div class="col-md-7">
<div class="row" id="app">
<!-- <member-form v-for="member in members" :key="member_form_component_id"></member-form>-->
</div>
<div class="row" id="add_button_div">
<button class="btn btn-primary m-2" type="button" id="id_btn_add_row"
v-on:click="add_member">Add Member</button>
</div>
</div>
<div class="col-md-2"></div>
</div>
</div>
</body>
<script type="text/x-template" id="member-form-template">
<div class="row" id="form-div-__prefix__">
<div class="row input-group input-group-md">
<div class="col border mx-auto">
<input type="text" name="member_set-__prefix__-first_name" placeholder="First Name" autocomplete="off"
class="form-control m-2" maxlength="100" id="id_member_set-__prefix__-first_name"
v-model="member_first_name">
</div>
<div class="col border mx-auto">
<input type="text" name="member_set-__prefix__-last_name" placeholder="Last Name" autocomplete="off"
class="form-control m-2" maxlength="100" id="id_member_set-__prefix__-last_name"
v-model="member_last_name">
</div>
<div class="col border mx-auto">
<input type="date" class="form-control m-2" name="member_set-__prefix__-dob" id="id_member_set-__prefix__-dob"
v-model="member_dob" #blur="joad_check">
</div>
<button class="btn btn-danger" id="id_member_button-__prefix__">Delete</button>
</div>
<div class="row input-group input-group-md border" id="form-div-__prefix__-joad" v-if="joad_seen">
<div class="col">To register for a JOAD session select start date:</div>
<div class="col">
<select name="member_set-__prefix__-joad" class="form-control m-2 costs" id="id_member_set-__prefix__-joad" v-model="member_joad">
<option value="" selected>None</option>
<option value="2020-05-24">2020-05-24</option>
</select>
</div>
</div>
</div>
</script>
js
var app1
var form_count = 0
var max_forms
var MemberForm
var MemberFormComponentId = 0
$(document).ready(function() {
app1 = new Vue({
el: '#app',
data: {
members: [],
},
methods: {
add_member: function() {
let v = new Vue({
el: "#form-div-" + form_count,
created: function() {
$("#app").html($("#app").html() + $("#member-form-template").html().replace(/__prefix__/g, form_count))
},
data: {
seen: false,
first_name: $("#id_member_set-" + form_count + "-first_name"),
last_name: $("#id_member_set-" + form_count + "-last_name"),
dob_id: $("#id_member_set-" + form_count + "-dob"),
joad: $("#id_member_set-" + form_count + "-joad"),
form_id: form_count,
},
methods: {
joad_check() {
if (this.member_dob === "") {
return false
}
var bd = new Date(this.member_dob);
var joad_date = new Date();
joad_date.setFullYear(joad_date.getFullYear() - 21);
this.joad_seen = (bd > joad_date && bd < new Date())
},
disable_delete () {
$("#id_member_button-"+ this.form_id).prop('disabled', true);
}
},
mounted: function () {
if(this.form_id == 0) {
$("#id_member_button-"+ this.form_id).prop('disabled', true);
}
}
})
this.members.push(v)
form_count++
MemberFormComponentId++
if( form_count > max_forms) {
$("#id_btn_add_row").prop('disabled', true);
} else {
$("#id_btn_add_row").prop('disabled', false);
}
}
}
})
app1.add_member()
})

Cannot use 'in' operator to search for 'xxxxx' in undefined in vue.js

I'm trying to create a modal form that will add a record. I am able to display the default values from data but as soon as I try to modify the field, I get the following error whenever I try to type changes to the input box.
*vue.min.js:6 TypeError: Cannot use 'in' operator to search for 'fullname' in undefined
at a.ke [as $set] (vue.min.js:6)
at input (eval at Ya (vue.min.js:1), <anonymous>:3:2182)
at He (vue.min.js:6)
at HTMLInputElement.n (vue.min.js:6)
at HTMLInputElement.Yr.o._wrapper (vue.min.js:6)*
In given Below I added the code of the component I'm trying to create:
Any help, please.
var bus = new Vue();
Vue.component('leagues_add', {
props: {
show: Boolean,
is_admin: Boolean,
},
data: function () {
return {
newLeague: {"fullname":"a", "notes":"b", "group_image_path": "c"} // remember to always enclose the fieldnames in doublequotes
}
},
methods: {
closeModal() {
this.show = false;
},
showModal() {
this.show = true;
},
addLeague() {
event.preventDefault();
var formData = this.toFormData(this.newLeague);
axios.get("http://"+ window.location.hostname +"/db/leagues/index.php?action=create").then(function(response){
if (response.data.error) {
app.errorMessage = response.data.message;
} else {
app.leagues = response.data.leagues;
}
});
},
toFormData(obj) {
var fd = new FormData();
for (var i in obj) {
fd.append(i, obj[i]);
}
return fd;
},
}
,
template:
`
<!-- Add new Leage -->
<div>
<div class="text-center pb-3" >
<button type="button" class="btn btn-outline-primary bg-success text-white" #click="showModal"><b class="" style="">Add League</b></button>
</div>
<transition name="modal">
<div id="overlay" v-show="this.show">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add League</h5>
<button type="button" class="close" #click="closeModal"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
<form action="#" method="POST">
<div class="form-group">
<input type="text" v-model="this.newLeague.fullname" class="form-control form-control-md" placeholder="Name of League">
</div>
<div class="form-group">
<textarea v-model="this.newLeague.notes" rows="3" cols="100%" name="notes" class="form-control form-control-md" placeholder="Describe this league">
</textarea>
</div>
<div class="form-group form-inline ">
<div class="col-12 p-0">
<input type="url" v-model="this.newLeague.group_image_path" class="col-5 pull-left form-control form-control-md" placeholder="Image URL">
<button class="col-4 btn btn-primary btn-md">Image</button>
</div>
</div>
<div class="form-group">
<button class="btn btn-info btn-block btn-md" #click="closeModal();addLeague();">Add this league</button>
</div>
</form>
</div>
</div>
</div>
</div>
</transition>
<div>
`
});
<div class="row">
<div class="col-md-12">LEAGUES SECTION</div>
</div>
<div class="row mt-2">
<div class="col-md-12">
<leagues_add :show="true" />
</div>
</div>
The problem is here:
v-model="this.newLeague.fullname"
You cannot use this. with v-model. Instead it should be:
v-model="newLeague.fullname"
You should also remove all other references to this within your template. In many cases they are harmless but sometimes, such as with v-model, they will cause problems.
Complete examples below. Note how the first input does not function correctly when editing the text.
new Vue({
el: '#app1',
data () {
return { newLeague: { fullname: 'League 1' } }
}
})
new Vue({
el: '#app2',
data () {
return { newLeague: { fullname: 'League 1' } }
}
})
<script src="https://unpkg.com/vue#2.6.11/dist/vue.js"></script>
<div id="app1">
<input type="text" v-model="this.newLeague.fullname">
{{ newLeague.fullname }}
</div>
<div id="app2">
<input type="text" v-model="newLeague.fullname">
{{ newLeague.fullname }}
</div>
I followed the way #skirtle wrote the data section and it worked.
My original syntax was:
data: function () {
return {
newLeague: {"fullname":"a", "notes":"b", "group_image_path": "c"} }
}
to
data () {
return { newLeague: { fullname: 'League 1' } }
}

Local-Storage in Vue.JS

I am working on Vue.JS and I tried to use local-storage with it to save data. In my code, I can store and retrieve all data with local-storage except line-through effect. Here, I am trying to store actual boolean value of line-through effect in local-storage and want to retrieve that value on to-do list app.
<title>To Do List</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'></script>
<style>
.taskDone {
text-decoration: line-through;
}
</style>
</head>
<body>
<div id="todo-list" class="container">
<div class="container col-sm-8 col-sm-offset-2">
<h1 class="text-center"> <big><b> To Do List </b> </big></h1>
<h5 class="text-center"> <span v-show="itemsTodo.length"> ({{ itemsTodo.length }} pending) </span></h5>
<div class="col-md-8">
<button v-if="state === 'default'" class="btn btn-primary" #click="changeState('edit') ">Add Item</button>
<button v-else class="btn btn-info" #click="changeState('default')">Cancel</button>
</div>
<br>
<br>
<div v-if="state === 'edit'" >
<div class="col-sm-4">
<input class='form-control' v-model="newItem" type="text" placeholder="Type here" #keyup.enter="saveItem" >
</div>
<div class="col-sm-4">
<input class="form-control" v-model="newdate" type="date" type="text"/>
</div>
<div class="col-sm-4">
<button class='btn btn-primary btn-block' v-bind:disabled="newItem.length === 0"#click= "saveItem">Save Item</button>
</div>
</div>
<br>
<br>
<ul type="none" class="list-group">
<li class="list-group-item" v-for="(item,index,date) in items" :class="{taskDone : item.completed}" >
<h4>
<input type="checkbox" v-model="item.completed" #click="item.completed = !item.completed">
<button class="btn btn-primary " #click.stop="removeitems(index)">× </button>
<b><i> {{ item.label }} {{ item.date }} </i></b></h4>
</li>
</ul>
<h2 v-if="items.length === 0">Nice Job! Nothing in TO DO LIST</h2>
<div class="col-sm-4">
<button class="btn btn-warning btn-block" #click="clearcompleted"> Clear Completed</button>
</div>
<div class="col-sm-4">
<button class="btn btn-danger btn-block" #click="clearAll"> Clear All</button>
</div>
</div>
</div>
2. Vue.JS code
<script src="https://unpkg.com/vue" ></script>
<script>
var todolist = new Vue({
el: '#todo-list',
data : {
state : 'edit',
header: 'To Do List',
newItem: '',
newdate: '',
items: [
{
label:'coffee',
completed:false,
date:'2019-06-20' ,
},
{
label:'tea',
completed:false,
date:'2019-06-19' ,
},
{
label:'milk',
completed:false,
date:'2019-06-19' ,
},
]
},
computed:{
itemsDone(){
return this.items.filter(items => items.completed)
},
itemsTodo(){
return this.items.filter(items =>! items.completed)
},
},
methods:{
saveItem: function(){
if (this.newItem != ''){
this.items.push({
label:this.newItem,
completed: false,
date : this.newdate,
});
this.newItem = '';
this.newdate = '';
}},
changeState: function(newState){
this.state = newState;
this.newItem = '';
this.newdate = '';
},
removeitems(index){
this.items.splice(index,1);
},
clearcompleted (){
this.items = this.itemsTodo;
},
clearAll: function(){
this.items = [ ];
},
},
mounted(){
console.log('App Mounted!');
if (localStorage.getItem('items')) this.items = JSON.parse(localStorage.getItem('items'));
},
watch: {
items:{
handler(){
localStorage.setItem('items',JSON.stringify(this.items));
},
},
},
});
</script>
I expect correct boolean value of line-through effect to be stored in local-storage. So that, appropriate effect will show on browser.
You are just watching items. If you change something in a item (in your case completed) the handler will not be called and your change is not stored.
You could use a "deep" watcher but i suggest to call your save logic whenever you changed something.

vuejs :disabled doesn't work

I have a problem on reactivating the button even if the conditional statement works.
it looked like the v-model wasn't communicating with the data but with a simple interpolation the value was updated.
I don't really know where I'm doing wrong on the code.
<template>
<div class="col-sm-6 col-md-4">
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">{{stock.name}}
<small>(Price: {{stock.price}})</small>
</h3>
</div>
<div class="panel-body">
<div class="pull-left">
<input v-model="quantity" type="number" class="form-control" placeholder="Quantity">
</div>
<div class="pull-right">
<button class="btn btn-success" #click="buyStock" :disabled="isDisabled">Buy</button>
</div>
<p>{{quantity}}</p>
</div>
</div>
</div>
</template>
<script>
export default {
props: [
"stock",
],
data() {
return {
quantity: 0,
}
},
methods: {
buyStock() {
const order = {
stockId: this.stock.id,
stockPrice: this.stock.price,
quantity: this.quantity
};
console.log(order);
this.$store.dispatch("buyStock", order);
this.quantity = 0;
}
},
computed: {
isDisabled() {
if (this.quantity <= 0 || !Number.isInteger(this.quantity)) {
return true;
} else {
return false;
}
}
}
}
</script>
By default, the v-model directive binds the value as a String. So both checks in your isDisabled computed will always fail.
If you want to bind quantity as a number, you can add the .number modifier like so:
<input v-model.number="quantity" type="number" ... >
Here's a working example:
new Vue({
el: '#app',
data() {
return { quantity: 0 }
},
computed: {
isDisabled() {
return (this.quantity <= 0 || !Number.isInteger(this.quantity))
}
}
})
<template>
<div class="col-sm-6 col-md-4">
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">{{stock.name}}
<small>(Price: {{stock.price}})</small>
</h3>
</div>
<div class="panel-body">
<div class="pull-left">
<input v-model="quantity" type="number" class="form-control" placeholder="Quantity">
</div>
<div class="pull-right">
<button class="btn btn-success" #click="buyStock" :disabled="isDisabled">Buy</button>
</div>
<p>{{quantity}}</p>
</div>
</div>
</div>
</template>
<script>
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
<input v-model.number="quantity" type="number">
<button :disabled="isDisabled">Foo</button>
</div>

How to hide / show component in vuejs

I'm developing a small application in VueJs where I'm having a div element and trying to show element if the data value is 1 and hide if the data value is 0, for this I'm having v-model as withClient something like this:
<div class="col-sm-6">
<label class="col-sm-6 control-label">With client*:</label>
<div class="radio col-sm-3">
<input type="radio" name="with_client" v-model="withClient" value="1" checked="">
<label>
Yes
</label>
</div>
<div class="radio col-sm-3">
<input type="radio" name="with_client" v-model="withClient" value="0">
<label>
No
</label>
</div>
</div>
And the element which needs to be hidden:
<div class="col-sm-6">
<label class="col-sm-3 control-label">Clients:</label>
<div class="col-sm-8" v-if="withClientSelection">
<v-select
multiple
:options="contactClients"
:on-search="getOptions"
placeholder="Client name"
v-model="clientParticipants">
</v-select>
</div>
</div>
I've computed property as withClientSelection:
withClientSelection() {
if(this.withClient === 0)
{
this.clientParticipants = ''
return false
}
else
{
return true
}
}
But somehow I'm not able to get this. Help me on this. Thanks
It's actually very simple, you should use
this.withClient === '0'
instead of
this.withClient === 0
I also overlooked this part and verified your code myself first, here's a fully working example that I used.
Vue.component('v-select', VueSelect.VueSelect);
const app = new Vue({
el: '#app',
data: {
withClient: '0',
clientParticipants: '',
dummyData: ['Aaron', 'Bart', 'Charles', 'Dora', 'Edward', 'Flora', 'Gladys', 'Heidi', 'Iris', 'Jason'],
contactClients: []
},
computed: {
withClientSelection() {
if (this.withClient === '0') {
return false
}
return true
}
},
watch: {
withClient(newVal) {
if (newVal === 0) {
this.clientParticipants = '';
}
}
},
methods: {
getOptions(search, loading) {
/*
loading(true)
this.$http.get('https://api.github.com/search/repositories', {
q: search
}).then(resp => {
this.contactClients = resp.data.items
loading(false)
})
*/
this.contactClients = this.dummyData
.filter((name) => name.toLowerCase().indexOf(search.toLowerCase()) >= 0);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-resource#1.3.4"></script>
<script src="https://unpkg.com/vue-select#latest"></script>
<div id="app">
<div class="col-sm-6">
<label class="col-sm-6 control-label">With client*:</label>
<div class="radio col-sm-3">
<input type="radio" name="with_client" v-model="withClient" value="1" checked="">
<label>
Yes
</label>
</div>
<div class="radio col-sm-3">
<input type="radio" name="with_client" v-model="withClient" value="0">
<label>
No
</label>
</div>
</div>
<div class="col-sm-6">
<label class="col-sm-3 control-label">Clients:</label>
<div class="col-sm-8" v-if="withClientSelection === true">
<v-select
multiple
:options="contactClients"
:on-search="getOptions"
placeholder="Client name"
v-model="clientParticipants">
</v-select>
</div>
</div>
<div class="col-sm-6">
<label class="col-sm-3 control-label">Selected Clients:</label>
<div class="col-sm-8" v-if="withClientSelection === true">
{{clientParticipants}}
</div>
</div>
</div>
I think the intention with v-model on hidden inputs is to set up a one-way binding, in which case it's much better to use
<input type="hidden" :value="someData" >
You can try this, it will help you to solve your problem.
new Vue({
el: '#app',
data: {
clientParticipants: '',
withClientSelection: 1
},
methods: {
checkMe: function(type) {
return this.withClientSelection = type
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<div class="col-sm-6">
<label class="col-sm-6 control-label">With client*:</label>
<div class="radio col-sm-3">
<input type="radio" name="with_client" #change="checkMe(1)" checked="">
<label>
Yes
</label>
</div>
<div class="radio col-sm-3">
<input type="radio" name="with_client" #change="checkMe(0)">
<label>
No
</label>
</div>
</div>
<div class="col-sm-6">
<label class="col-sm-3 control-label">Clients:</label>
<div class="col-sm-8" v-if="withClientSelection">
Display now!
<v-select
multiple
:options="contactClients"
:on-search="getOptions"
placeholder="Client name"
v-model="clientParticipants">
</v-select>
</div>
</div>
</div>