Set v-checkbox programmatically using Vue and Vuetify - vue.js

I'm building a list of v-checkboxes using this code
<div class="row form-group" v-for="(author, key) in authorData" :key="key">
<v-layout row wrap>
<v-flex xs1 sm1 md1 text-xs-center>
<div>
<v-checkbox
label
:key="author.PmPubsAuthorID"
v-model="authorData[key].checked"
v-bind:id="author.PmPubsAuthorID.toString()"
color="success"
#change="authorCBClicked(authorData[key])"
></v-checkbox>
</div>
The PmPubsAuthorID is a number like 1047602 and is a sequential number in the entire database, no 2 records are the same. When I run the code to build the list it works fine and shows a checkbox if the value is true. What I am trying to do is when a checkbox is checked in the
authorCBClicked(author) {
//PmPubsAuthorID = 1047602
// alert(author.PmPubsAuthorID + " " );
// author.checked = false; does not work
this.authorData[author.PmPubsAuthorID].checked = false; does not work
this.authorData["1047602"].checked = false; does not work
this.authorData[1047602].checked = false; does not work
this.authorData[2].checked = false; does work
},
As you can see I have tried various ideas and the only one that seems to work is passing in an ordinal but I have no way of knowing that. Do I need to use an index when building the checkboxes?
The reason: I have a checkbox then when checked calls a dialog box that asks " Are you sure you want to "Add this item to the list" if they say yes I want the original checkbox to be checked but if they say no then the original checkbox needs to be false. I have found that if I try to set the checked status of the calling checkbox to false it does not work but works fine once outside that method. I have passed the key and author information to the new dialog and let it change the checkbox to false if needed
Thanks for the help.

Just pass the key instead of the whole item to your method :
#change="authorCBClicked(key)"
and on your method :
authorCBClicked(key) {
this.authorData[key].checked = !this.authorData[key].checked;
}
Or :
you can do it directly on the template :
#change="author.checked = !author.checked"

Related

Vuetify text-field won´t use computed property

I would like a clearable v-text-field with a label to show a computed string property based on other another property (a boolean in this simplified example).
Initially it works, the correct default string value is shown.
If I invert the boolean with a button from outside the v-text-field component, the next correct string value is shown as expected.
But if I use the clear button in the v-text-field to invert the boolean, the v-text-field clears and uses the label in the input field when focus is lost, and therefore not using the expected string value.
Input:
<v-text-field :value="text" label="Just a label" clearable #click:clear="booleanModel = true;"></v-text-field>
Computed property:
text: function() {
if(this.booleanModel) {
return 'Its on'
} else {
return 'Default text';
}
}
As far as I can see via vue dev tools, the state in the v-text-field is the same either way.
How come, and how to avoid this?
Please refer to this example: https://codepen.io/fasterlars/pen/RwKrzXZ?editors=1010
To be honest your use-case seems very strange but...
The problem is that v-text-box has some internal state (according to source code comments to make it work without the model) and on clear icon click it sets it to null but it does this in the nextTick - source. This is little bit strange but they probably has some reasons to do so...
So if you don't want to really clear the content but instead set it to something else, do not use default "clearable" functionality and use append slot instead:
<v-text-field :value="text" label="Just a label">
<template v-slot:append>
<v-icon #click="booleanModel = true">clear</v-icon>
</template>
</v-text-field>
When you click on the clear button, the value of booleanModel does not change.
You need to update the #click:clear = "booleanModel = false;".
Also, add a :key="booleanModel in your text field, which will ensure that whenever the value of booleanModel changes it will re-render the v-text-field component again.

render button based on checkbox count

I'm trying to disable or enable a button based on checkboxes. if two more are checked the button is no longer disabled. This part works but I'm not sure how to disable the buttons again if I uncheck items.
i'm new to vue but I'm wondering how to find out if each checkbox has been either checked OR unchecked so I can correctly move my counter up or down.
<li class="listItemsModal" v-for="(student, index) in students">
<input v-model="student.exclude" #change="toggleAddButton" id="student.index" type="checkbox" >
{{student.first_name}}
</li>
if the button is clicked we add and check to see if the value is bigger than 2
I need some way to access the checked value to see if checked or not, then go up or down accordingly
toggleAddButton: function(){
console.log(this.studentsAdded)
this.studentsAdded ++
if(this.studentsAdded >= 2){
this.disableAdd = false
}else{
this.disableAdd = true
}
}
There are a bunch of ways to do this, some are easier or harder depending on your data structures.
If your students array is fully reactive you could have a computed property that updates any time that object changes. Something like:
// ... vue stuff...
computed:{
// ... your other computed properties
enoughBoxesChecked(){
// you could also use an accumulator, but this is very easy to read.
return this.students.filter(student=>student.exclude).length > 2;
}
}
// ... other vue stuff
Then you could use that enoughBoxesChecked computed property on the button you want to disable. Something like <button :disabled="enoughBoxesChecked">....

Editing fields with Vue & Vuex

I have a page where I want a user to be able to edit their room information. For example the name of the room. The code I have currently is that it shows the roomName in an h3 and if they click on the edit button, then the property edit is changed to true (this will then show the text-field instead of the h3).
<!-- Room Name -->
<h2 v-if="edit == false">{{ roomName }}</h2>
<!-- EDIT -->
<v-text-field
v-else
label="Room Name"
v-model="roomName"
/>
<!--Edit Button-->
<v-btn v-if="edit == false"
#click="edit = true"
class="filter">Edit</v-btn>
<!--Cancel Button-->
<v-btn v-if="edit == true"
#click="cancelEdit"
class="filter">Cancel</v-btn>
The problem is: That if a user presses cancel I don't want it to update the property roomName. I try to do this by rerunning a computed property that grabs the roomName from the store. However I doesn't allow me to call a computed property in cancelEdit.
The reason I'm using a roomName property & v-model, and not directly using the value from the computed property is... because I don't understand how I can grab the value from an input if I press save.
How can I grab the value from an input or how can I make a cancel button with this structure?
Check this snippet to see if it can help you,
I didn't use vuex but you can your initial values from your store:
https://jsbin.com/yefiqinewu/edit?html,js,output

polymer dom-if does not re check the condition

I have a simple dom-if in a template:
<div>
<template is="dom-if" if="{{checkListEmpty()}}" restamp>
<paper-button raised class="init" on-tap="initialize">Initialize</paper-button>
</template>
</div>
and a function to show or hide.
checkListEmpty() {
return this.todos.length == 0;
}
It works for the first time only. If the this.todos.length becomes 1 then the template does not goes away. How can i hide when the condition is false.
There is no binding working for your function because there is no property to bind.
To make it work you should add a property in parameter : checkListEmpty(foo).
Like that, everytime the property foo change the function will be executed.
However an array as property won't work if the content of this one changed (content pushed) except if this is the global array property that is replaced :
var bar = [], foo = ["ggg"];
bar = foo;
In that case the function will be called, but it's not great.
Anyway for your question you can use an hidden property for the paper-button or bind the DOM-IF with the table length.
<template is="dom-if" if="[[!bar.length]]" restamp>
<paper-button raised on-tap="addBar">Initialize</paper-button>
</template>
or
<paper-button raised on-tap="addBar" hidden="[[bar.length]]">Initialize</paper-button>
And then everytime a property is added into the array or removed until there is nothing in it your button will be displayed or not.
You can see a working jsfiddle (use chrome though and be patient for the initialization.. comment here if it's not working)

Selecting specific element in vue 2 inside v-for loop

Please see the code
<div v-for="msg in leftMsg">
div v-if="msg.last_sender" #click.prevent="loadMsg(msg)">
<tr :class="['active',{ 'seens' : !msg.seen, 'selected':msg.isActive}]">
// some html
</tr>
</div>
</div>
loadMsg(obj){
obj.isActive = !obj.isActive;
}
The problem is, it is adding selected class properly but when I click another item it adds selected but doesn't remove the old one. How can I keep only the most recent clicked item selected?
Thank you.
Add a data property outside of the msg objects and use that to track the active message.
data(){
return {
activeMessage: null,
...
}
}
Then in your template, set the activeMessage.
<div v-for="msg in leftMsg">
<div v-if="msg.last_sender" #click.prevent="activeMessage = msg">
<tr :class="['active',{ 'seens' : !msg.seen, 'selected': msg === activeMessage}]">
// some html
</tr>
</div>
</div>
The key parts I changed here are #click.prevent="activeMessage = msg" and 'selected': msg === activeMessage. This will set activeMessage to the clicked message, and then the selected class will be applied to the activeMessage and will only apply to the activeMessage.
I would also note that it's strange that you have a tr element nested inside div. I assume it was just because of your example, but that's not technically valid HTML.
I have solved this issue using a for loop. I thought it may help some other.
In order to remove the all other previous active classes all you need to run a for loop and make them false and then assign active=true to the newest one.
Here is the code that may help
// make all other selected class false first
for(let i=0; i<this.leftMsg.length; i++){
this.leftMsg[i].isActive=false;
}
/*now making the newest one active*/
obj.isActive = true;