call to two functions in v-checkbox onchange event in vue js - javascript

I'm using vue js with vuetify and laravel. I have a component with a dynamic datatable which gets data from database using axios. Also there's v-checkboxes in that datatable. So everything is working as i expect. But now I want to call to two functions onchange event in v-checkbox. For example when user click the checkbox (checked) I want to call to a save function and when user uncheck the checkbox I want to call to a delete function. I tried to do it with the id of the v-checkbox and check if that checkbox is checked then call to save function else call to delete function. And then when user checked the checkbox save function get called but when user uncheck the checkbox both functions get called. That's where I'm stuck at. How can I archieve this?
datatable
<v-data-table :headers="customer_headers" :items="customers" :search="customer_search" item-key="CustomerCode" ref="customer_table">
<template slot="items" slot-scope="props">
<tr :id="'customer_tr_'+props.item.CustomerCode">
<td class="text-md-center">{{ props.item.CustomerCode }}</td>
<td class="text-md-center">{{ props.item.CustomerName }}</td>
<td class="text-md-center">{{ props.item.NO_OF_DISPENSERS }}</td>
<td class="text-md-center">{{ props.item.next_service_date }}</td>
<td class="text-md-center">{{ props.item.STATUS }}</td>
<td class="text-md-center">{{ props.item.Workerstatus }}</td>
<td class="text-md-center">
<v-checkbox
:key="props.item.CustomerCode"
:ref="'customer_checkbox_ref' + props.item.CustomerCode"
:id="'customer_checkbox_'+props.item.CustomerCode"
#change="loadCustomerDispensers(props.item.CustomerCode,props.item.STATUS);changeServicePlanData()"
></v-checkbox>
</td>
</tr>
</template>
</v-data-table>
I 'm trying this in changeServicePlanData() functionchangeServicePlanData()
function changeServicePlanData(id) {
if ($('#' + id).checked == true) {
this.savePlan()
} else {
this.deletePlan()
}
}

I would say you don't need jQuery for this. There are several approaches to achieving this on v-checkbox, one being the use of Checkboxes selected values as Array.
Consider the following example:
new Vue({
el: '#app',
data() {
return {
items: [{
label: 'Item #1',
value: 1
},
{
label: 'Item #2',
value: 2
},
{
label: 'Item #3',
value: 3
}
],
selected: [2] // Preselects Item #2
}
},
methods: {
check(val) {
let action = '';
if (this.selected.includes(val)) {
action = 'Saving';
}
else {
action = 'Deleting';
}
alert(`${action} plan #${val}`);
}
}
});
.v-input {
margin-top: 0 !important;
}
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
<div id="app">
<v-app>
<v-container fluid>
<v-checkbox v-model="selected"
v-for="item in items"
:key="item.value"
:label="item.label"
:value="item.value"
#change="check(item.value)"></v-checkbox>
</v-container>
</v-app>
</div>
So, in your case, I would do something like so:
<v-data-table
:headers="customer_headers"
:items="customers"
:search="customer_search"
item-key="CustomerCode"
ref="customer_table">
<template slot="items" slot-scope="{ item }">
<tr>
<!-- the other TDs here -->
<td class="text-md-center">
<v-checkbox
v-model="selectedCustomerCodes"
v-bind:value="item.CustomerCode"
label="Service plan data"
#change="loadCustomerDispensers(item.CustomerCode, item.STATUS)">
</v-checkbox>
</td>
</tr>
</template>
</v-data-table>
data() {
return {
selectedCustomerCodes: []
}
},
methods: {
loadCustomerDispensers(customerCode, status) {
// Your business logic
this.changeServicePlanData(customerCode);
},
changeServicePlanData(code) {
if (this.selectedCustomerCodes.includes(code)) {
this.savePlan();
}
else {
this.deletePlan();
}
},
savePlan() {
// ...
},
deletePlan() {
// ...
}
}

Related

Hide specific row of a table

I have this simple table:
<v-simple-table>
<template v-slot:default class="my-20 py-20">
<thead>
<tr>
<th class="text-left">Attribute</th>
<th class="text-left">Operator</th>
<th class="text-left">Values</th>
</tr>
</thead>
<tbody>
<tr v-for="(ruleDetail, j) in ruleDetails">
<td>{{ ruleDetail.attribute_name }}</td>
<td>{{ ruleDetail.operator_name }}</td>
<td>{{ ruleDetail.value }}</td>
</tr>
</tbody>
</template>
</v-simple-table>
I would like to hide the row where
ruleDetail.attribute_name == Label batch
What is the best practice to do that?
//all from API
//this.ruleDetails = response.data.details
//tried to filter, but it's not working.
this.ruleDetails = response.data.campaigns.filter((item) => {
return item.attribute_name != 'Label batch'
})
Try to use includes in filter in computed property :
computed: {
filteredRules() {
return this.ruleDetails.filter((item) => !item.attribute_name.toLowerCase().includes(('Label batch').toLowerCase())
}
}
and then in templae:
<tr v-for="(ruleDetail, j) in filteredRules">
Your code is perfect and it should work. One suggestion, cross check response.data.campaigns to see if you are getting the proper response in this or not.
Working Demo as per the code you posted :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
campaigns: [
{
attribute_name: 'UV Index (Current Weather)',
operator_name: 'Lesser number',
value: 7
},
{
attribute_name: 'Temperature (Current Weather)',
operator_name: 'Greater or equal number',
value: 17
},
{
attribute_name: 'Label batch',
operator_name: 'Equal numbers',
value: 66235
}
],
ruleDetails: []
}
},
mounted() {
this.ruleDetails = this.campaigns.filter((item) => {
return item.attribute_name != 'Label batch'
})
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.6.4/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify#2.6.4/dist/vuetify.min.css"/>
<div id="app">
<v-app id="inspire">
<v-simple-table>
<template v-slot:default>
<thead>
<tr>
<th class="text-left">Attribute</th>
<th class="text-left">Operator</th>
<th class="text-left">Values</th>
</tr>
</thead>
<tbody>
<tr v-for="(ruleDetail, j) in ruleDetails">
<td>{{ ruleDetail.attribute_name }}</td>
<td>{{ ruleDetail.operator_name }}</td>
<td>{{ ruleDetail.value }}</td>
</tr>
</tbody>
</template>
</v-simple-table>
</v-app>
</div>

Vue.js disabled button with condition doesn't work

I have a data-table in Vue.js component using Vuetify with a input inside a row, and I need to disable a button if the input v-model="row.item.quantidade" was empty. but doesn't work.
HTML
<v-data-table :headers="headersAllStep3" :items="step2" :search="searchAllStep3">
<template v-slot:item="row">
<tr>
<td>{{ row.item.produto }}</td>
<td>{{ row.item.descricao }}</td>
<td>{{ row.item.ncm }}</td>
<td><input type="number" v-model="row.item.quantidade" autofocus></td>
</tr>
</template>
</v-data-table>
<v-btn :disabled="isDisableQuantidade()">
Continue
</v-btn>
Javascript method in vue.js component
isDisableQuantidade(){
return this.step2.quantidade.length == false;
},
The function :
isDisableQuantidade(){
return this.step2.some(step=>step.quantidade==0);
},
should be a computed property and it must be used without () like :
<v-btn :disabled="isDisableQuantidade">
Continue
</v-btn>

Vee validate v3 ValidationObserver not working with dynamic validation provider added using v-for

I am using Vee Validate v3 for validating dynamic input generated using V-FOR, which is added or removed input elements based on user actions.
My issue was only the last input gets validated other inputs not getting validated. In the documentation, they had mentioned this issue while using V-IF & V-FOR
documentation link
They told to use VueJS keep-alive component. but not working with V-FOR.
<validation-observer ref="observer" v-slot="{ handleSubmit }">
<form method="POST" action="{{ route('app.store') }}" #submit.prevent="handleSubmit(onSubmit)" class="form" enctype="multipart/form-data">
<table class="table">
<thead>
<tr>
<th>SI No</th>
<th>input 1</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in items" :key="item.id">
<td>#{{ index + 1 }}</td>
<td>
<keep-alive>
<validation-provider rules="required" v-slot="{ errors }" name="attribute">
<div class="form-group">
<input :name="'attribute' + item.id" class="form-control" v-model="item.attribute">
<span class="error" role="alert">
#{{ errors[0] }}
</span>
</div>
</validation-provider>
</keep-alive>
</td>
<td>
<button type="button" class="btn btn-md btn-danger mt-4" #click="remove(index)">
<span class="ion-trash-a"></span>
</button>
</td>
</tr>
</tbody>
</table>
<x-form-submit>Save</x-form-submit>
</form>
My js code
<script type="application/javascript">
Vue.component('dynamic-form-wrapper', {
template: '#dynamic-form-template',
data() {
return {
items: [
{
id: 1,
attribute: null,
},
{
id: 2,
attribute: null,
}
],
id: 3
}
},
methods: {
async onSubmit() {
const valid = await this.$refs.observer.validate();
if (valid) {
document.getElementById("category-form").submit();
}
},
add() {
this.items.push({
id: this.id,
attribute: null,
});
this.id ++;
},
remove(index) {
if (this.items.length != 1) {
this.items.splice(index, 1);
}
}
}
})
</script>
Thanks in advance
Each ValdationProvider needs a unique id. set :vid for each validation providers
<keep-alive>
<validation-provider :vid="'attribute' + item.id" rules="required"
v-slot="{ errors }" name="attribute">
<x-v-form-input type="text" v-model="item.attribute" field="attribute">
</x-v-form-input>
</validation-provider>
</keep-alive>
Refer API docs for vid here: https://vee-validate.logaretm.com/v3/api/validation-provider.html#props

How to set focus on textarea which is rendered inside v-for in Vuejs 2?

In my Vue.js component, I rendered table rows containing textarea based on a list of items as following:
<template>
<div>
<table>
<tr v-for="(item, index) in items">
<td>{{ index }}</td>
<td><textarea v-model="item.message"></textarea></td>
</tr>
</table>
</div>
</template>
<script>
export default {
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
};
</script>
When I click anywhere in a row, I want the textarea inside that row to be focused. How can I do that?
The following code cannot solve the problem:
this.$refs.myTextArea.focus();
This only works with element with unique ref id and outside of v-for.
Try to specify an unique ref name to each text area like :
<tr v-for="(item, index) in items" #click="focus('ta'+index)">
<td>{{ index }}</td>
<td><textarea v-model="item.message" :ref="'ta'+index"></textarea></td>
</tr>
focus method :
methods:{
focus(key){
this.$refs[key][0].focus()
}
}
check this demo
Have you tried adding a dynamic value for ref on each row?
Then you can react to click events and select the proper textarea based on that attribute.
Something like:
<template>
<div>
<table>
<tr v-for="(item, index) in items" v-on:click="focusTextArea(index)">
<td>{{ index }}</td>
<td>
<textarea ref="textArea{{index}}" v-model="item.message"></textarea>
</td>
</tr>
</table>
</div>
</template>
<script>
export default {
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
},
methods: {
focusTextArea: (textAreaIndex) => {
this.$refs[`textArea{textAreaIndex}`].$el.focus();
}
}
};
</script>

VueJs Filtering Between Dates in table

I have a question for you guys, I have a table that contains student time information and dates, for the quarter. I would like to add a time picker so the instructors can select to show just the information between this date and that day.
Basically, I want to use the Entry time field to filter and show just data from x date to x date.
Here is my code
<v-card>
<v-card-title>
Student Profile
<v-spacer></v-spacer>
</v-card-title>
<v-data-table :headers="headers2"
:pagination.sync="pagination2"
:items="profile"
:search="search">
<template slot="items" slot-scope="props">
<td>{{ props.item.sid }}</td>
<td class="text-xs-left">{{ props.item.firstName }}</td>
<td class="text-xs-left">{{ props.item.lastName }}</td>
<td class="text-xs-left">{{ props.item.course }}</td>
<td class="text-xs-left">{{ props.item.entryTime }}</td>
<td class="text-xs-left">{{ props.item.exitTime }}</td>
<td class="text-xs-left">{{ props.item.duration }}</td>
</template>
<v-alert slot="no-results" :value="true" color="error" icon="warning">
Your search for "{{ searchQuery }}" found no results.
</v-alert>
</v-data-table>
</v-card>
Method
methods: {
editStudent(sid) {
this.dialog = true;
this.editedSid = sid;
axios.get('/api/e', {
params: {
'sid': this.editedSid
}
}).then(response => {
this.profile = response.data
}).catch(e => {
console.log(e)
})
}
}
Any suggestions?
What you'll want to do is add a "computed property" that filters the original data, and use it instead.
something like
computed: {
filteredEntries(){
return this.profile.filter(entry => {
//check if the entry is between the selected dated
});
}
}
Then use 'this.filteredEntries' instead of 'this.profile' when initializing the table.

Categories

Resources