How to enable a disabled text-field with click - vue.js

I have two text-field in Vuetify, I want that when I click on one of them, the other one is disabled, so far I have managed to make it happen, but, I want that when I click on the disabled one, the text is enabled and disabled again previous-field.
This is the code of the component:
<v-row
v-for="(f, index) in fieldsFilter"
:key="index+'formfilterkey'"
class="pa-0 ma-0"
>
<template v-slot:activator="{ on, attrs }">
<v-text-field
v-model="f.value"
:label="f.label"
:disabled="f.disabled"
v-on:click="f.onClick"
readonly
clearable
dense
v-bind="attrs"
:rules="f.rule"
outlined
:required="f.required"
class="mx-3"
v-on="on"
/>
And the textfield properties are generated from another file.
created() {
this.fieldsFilterControl=[
{
type: "datepicker",
label: "Range 1",
value: null,
range: true,
menu: false,
disabled: 0,
onClick: ()=> {
this.fieldsFilterControl[1].disabled = true
}
},
{
type: "monthpicker",
label: "Range 2",
value: null,
range: true,
menu: false,
disabled: false,
onClick: ()=> {
this.fieldsFilterControl[0].disabled = true
}
},
],

Disabling a control also disables its events (it's by design).
I have a question for you - Does the text-field truly need to be disabled ?
As user can edit one text field at a time and this is how it will work if you disabled as well (as per your requirement).
Solution : You can add a toggle button against a disabled text field and on click of that button you can enable the specific text field and disable another one.
Live Demo :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
fieldsFilter: [
{
type: "datepicker",
label: "Range 1",
value: null,
range: true,
menu: false,
disabled: false
},
{
type: "monthpicker",
label: "Range 2",
value: null,
range: true,
menu: false,
disabled: false
}
]
}),
methods: {
onEnableDisable(index) {
this.fieldsFilter.forEach((obj, i) => {
obj.disabled = i === index ? false : true
});
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.6.10/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#2.6.10/dist/vuetify.min.css"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"/>
<div id="app">
<template>
<v-container class="grey lighten-5">
<v-row v-for="(f, index) in fieldsFilter"
:key="index"
class="pa-0 ma-0">
<v-col sm="4">
<v-text-field
v-model="f.value"
:label="f.label"
:disabled="f.disabled"
v-on:click="onEnableDisable(index)"
outlined
/>
</v-col>
<v-col>
<v-btn v-if="f.disabled" #click="onEnableDisable(index)">Enable Me</v-btn>
</v-col>
</v-row>
</v-container>
</template>
</div>

Related

Dynamic editable columns with vuetify data table

I am trying to make a vue data table component, I want to make it so that if you pass an array of column names, the values in those columns will be editable like in this example. I am currently trying to loop through the array prop passed to the component like as so...
<template
v-for="(column, index) in editableColumns"
v-slot:[getEditableColumn(column)]="props"
>
<v-edit-dialog
:return-value.sync="props.item.desk"
#save="save"
#cancel="cancel"
#open="open"
#close="close"
:key="index"
>
{{ props.item.desk }}
<template v-slot:input>
<v-text-field
v-model="props.item.desk"
label="Edit"
single-line
counter
></v-text-field>
</template>
</v-edit-dialog>
</template>
the get editable columns operates as such:
getEditableColumn(column) {
console.log(column);
return `item.${column}`;
},
it basically returns the value of the column I want to be editable as such item.columnName but the function never runs, I do have to mention that if I pass directly the name like this without a for loop it works, but I want this to work dynamically as I will use the table in multiple places with different column names, and I don't want to make them all columns editable editable.
Below I have attached the full code of the component.
<template>
<v-card>
<v-card-title>
{{ title || "" }}
<v-col>
<v-btn icon color="black" v-if="refresh">
<v-icon>mdi-refresh</v-icon>
</v-btn>
<v-btn icon color="black" v-if="exportExcel" #click="exportToXlsx">
<v-icon>mdi-microsoft-excel</v-icon>
</v-btn>
<v-btn icon color="black" v-if="exportPdf">
<v-icon>mdi-file-pdf-box</v-icon>
</v-btn>
<v-btn icon color="black" v-if="fontSizeControlls">
<v-icon>mdi-format-font-size-decrease</v-icon>
</v-btn>
<v-btn icon color="black" v-if="fontSizeControlls" #click="logSelected">
<v-icon>mdi-format-font-size-increase</v-icon>
</v-btn>
</v-col>
<v-spacer></v-spacer>
<v-col v-if="searchBar">
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Search"
outlined
dense
></v-text-field>
</v-col>
</v-card-title>
<v-data-table
#input="(selected) => $emit('selected', selected)"
#click:row="rowClickFunction"
v-model="selected"
:headers="headers"
:items="data"
:search="search"
:show-select="showSelect"
:single-select="singleSelect"
:height="height"
:items-per-page="itemsPerPage"
:item-key="itemKey"
dense
>
<!-- Pass template elements inside the component call to render custom components inside the table -->
<template
v-for="slot in Object.keys($scopedSlots)"
:slot="slot"
slot-scope="scope"
>
<slot :name="slot" v-bind="scope" />
</template>
<template
v-for="(column, index) in editableColumns"
v-slot:[getEditableColumn(column)]="props"
>
<v-edit-dialog
:return-value.sync="props.item.desk"
#save="save"
#cancel="cancel"
#open="open"
#close="close"
:key="index"
>
{{ props.item.desk }}
<template v-slot:input>
<v-text-field
v-model="props.item.desk"
label="Edit"
single-line
counter
></v-text-field>
</template>
</v-edit-dialog>
</template>
</v-data-table>
</v-card>
</template>
<script>
import { utils, writeFile } from "xlsx";
export default {
props: {
headers: Array,
data: Array,
title: String,
height: String,
itemsPerPage: Number,
itemKey: String,
searchBar: { tpye: Boolean, default: false },
rowClickFunction: {
type: Function,
default: () => {},
},
editableColumns: {
type: Array,
},
refresh: {
type: Boolean,
default: false,
},
exportExcel: {
type: Boolean,
default: false,
},
exportPdf: {
type: Boolean,
default: false,
},
fontSizeControlls: {
type: Boolean,
default: false,
},
singleSelect: {
type: Boolean,
default: false,
},
showSelect: {
type: Boolean,
default: false,
},
xlsxName: {
type: String,
default: "Sheet.xlsx",
},
},
data() {
return {
search: "",
selected: [],
dialog: false,
};
},
methods: {
exportToXlsx() {
const worksheet = utils.json_to_sheet(this.data);
const workbook = utils.book_new();
utils.book_append_sheet(workbook, worksheet, "Data");
writeFile(workbook, this.xlsxName);
},
getEditableColumn(column) {
console.log(column);
return `item.${column}`;
},
logSelected() {
console.log(this.selected);
},
logRow(row) {
console.log(row);
console.log(this.selected);
},
getSlotName(slot) {
return `${slot}.slotName`;
},
save() {
this.snack = true;
this.snackColor = "success";
this.snackText = "Data saved";
},
cancel() {
this.snack = true;
this.snackColor = "error";
this.snackText = "Canceled";
},
open() {
this.snack = true;
this.snackColor = "info";
this.snackText = "Dialog opened";
},
close() {
console.log("Dialog closed");
},
},
};
</script>
The slot name must be one of the headers element's value

How to use v-form inside a v-for and perform validation for a specific form?

I have an array of objects which I should loop through and show a form for each object's properties. The Save button is out of the for loop. In the attached sandbox, the 2nd object doesn't contain lastname. So, how do I perform validation on click of Save button only for the 2nd form? And is there any way to validate all the forms at once? Please refer to the sandbox for a better understanding.
https://codesandbox.io/s/jolly-kepler-m260fh?file=/src/components/Playground.vue
Check this codesandbox I made: https://codesandbox.io/s/stack-72356987-form-validation-example-4yv87x?file=/src/components/Playground.vue
You can validate all v-text-field at once if you move the v-form outside the for loop. All you need to do is give the form a ref value and a v-model to make use of the built in vuetify validation methods.
<template>
<v-container class="pl-10">
<v-form ref="formNames" v-model="validForm" lazy-validation>
<v-row v-for="(name, index) in names" :key="index">
<v-col cols="12">
<v-text-field
v-model="name.firstName"
outlined
dense
solo
:rules="rulesRequired"
/>
</v-col>
...
</v-row>
</v-form>
<v-btn type="submit" #click="submitForm" :disabled="!validForm">
Submit
</v-btn>
</v-container>
</template>
Then in the submit button all you need to do is call the validate() method of the form through the $refs object. You can also disable the submit button if any of the elements in the form don't pass the validation rules using the v-model of the form to disable the submit button.
<script>
export default {
name: "playground",
data: () => ({
validForm: true,
names: [
{
firstName: "john",
lastName: "doe",
age: 40,
},
{
firstName: "jack",
lastName: "",
age: 30,
},
],
rulesRequired: [(v) => !!v || "Required"],
}),
methods: {
submitForm() {
if (this.$refs.formNames.validate()) {
// Form pass validation
}
},
},
};
</script>
As submit button is outside of the forms. We can perform that validation on submit event by iterating the names array and check if any value is empty and then assign a valid flag value (true/false) against each object.
Demo :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
names: [
{
firstName: "john",
lastName: "doe",
age: 40,
valid: false
},
{
firstName: "jack",
lastName: "",
age: 30,
valid: false
},
],
requiredRule: [v => !!v || 'Value is required']
}),
methods: {
submitForm() {
this.names.forEach((obj, index) => {
if (!obj.lastName) {
obj.valid = false;
console.log(
`${index + 1}nd form is not valid as LastName is not available`
);
} else {
obj.valid = true;
}
});
// Now you can filter out the valid form objects based on the `valid=true`
}
}
})
<script src="https://unpkg.com/vue#2.x/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.6.6/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#2.6.6/dist/vuetify.min.css"/>
<div id="app">
<v-app id="inspire">
<v-container class="pl-10">
<v-row v-for="(name, index) in names" :key="index">
<v-form v-model="name.valid">
<v-col cols="12">
<v-text-field v-model="name.firstName" outlined dense solo required :rules="requiredRule" />
</v-col>
<v-col cols="12">
<v-text-field v-model="name.lastName" outlined dense solo required :rules="requiredRule" />
</v-col>
<v-col cols="12">
<v-text-field v-model="name.age" outlined dense solo required :rules="requiredRule" />
</v-col>
</v-form>
</v-row>
<v-btn type="submit" #click="submitForm"> Submit </v-btn>
</v-container>
</v-app>
</div>

Vuetify v-data-table custom filter for dropdown

I have a v-data-table that already has the :search and :sort-by enabled. I have now created a select where I pull in my status from VueX. Accepted, Rejected. What I want to do is not only search or sort but when selecting from the drop down, accepted only the accepted values display in the table.
<v-select
v-model="selectStatus"
label="Status"
:items="statusData"
item-value="id"
item-text="name"
return-object
#change="filterStatus"
/>
Is this the correct way to setup the filter?
methods: {
filterStatus () {
console.log('This is where I am planning to add my custom filter')
}
}
This is my statusData:
userStatus : [
{
id: 0,
name: "Accepted",
},
{
id: 1,
name: " Rejected",
},
];
Or better to pass in the data:
{ text: 'Status', value: 'status.name', filter: value => {}},
To disable certain values to be selected add a disabled property to your items.
var app = new Vue({
el: '#app',
vuetify: new Vuetify(),
data: {
items: [{
id: 0,
name: 'Accepted'
},
{
id: 1,
name: ' Rejected',
disabled: true
}
],
value: null
}
})
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.0"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<div id="app">
<v-app>
<v-container>
Value : {{value}}
<v-select
v-model="value"
label="Status"
:items="items"
item-value="id"
item-text="name"
return-object
/>
</v-container>
</v-app>
</div>
Documentation : props-disabled

Activity indicator not loading correctly in Vuetify

new Vue({
el: '#app',
vuetify: new Vuetify({
theme: {
dark: true
},
}),
data() {
return {
loading: null,
requests: [{"req_id":78},{"req_id":79}],
tableHeaders: [
{
text: 'ID',
value: 'req_id',
align: 'center',
},
{ text: 'Actions', value: 'action', sortable: false, align: 'center'},
],
createloading: false,
cancelloading: false,
};
},
methods: {
createPacks(item) {
this.loading = !this.loading;
item.createloading = true;
},
excludeRequest(item) {
this.loading =!this.loading;
item.createloading = false;
},
}
})
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify/dist/vuetify.min.js"></script>
<link href="https://unpkg.com/vuetify/dist/vuetify.min.css" rel="stylesheet"/>
<div id="app">
<v-app>
<v-row no-gutters class="align-start justify-start">
<v-col>
<v-row>
<v-data-table
:headers="tableHeaders"
:items="requests"
:loading="loading"
>
<template v-slot:item.action="{ item }">
<v-btn color="success" #click="createPacks(item)" :loading="item.createloading" :disabled="item.createloading">Create</v-btn>
<v-btn color="error" #click="excludeRequest(item)" :loading="item.cancelloading" :disabled="!item.createloading">Cancel</v-btn>
</template>
</v-data-table>
</v-row>
</v-col>
</v-row>
</v-app>
</div>
Please help me implement this code correctly, as it does not function correctly. The buttons should correctly show the loading indicator and should be independent.
Thank you in advance for your generosity.
Below is a link to codepen.
https://codepen.io/protemir/pen/MWwGaeO

Dynamically disable option in Vuetify overflow component

Vuetify disabled prop directly disabled input itself.I am trying to disable individual select option as per content on page.If we pass disabled="string" to items array (static arrangement).
How to make it dynamic.I have made Codepen for the same https://codepen.io/spider007/pen/eYmLBOG
<div id="app">
<v-app id="inspire">
<v-container>
<v-overflow-btn
class="my-2"
:items="items"
label="Overflow Btn - Dense"
dense
v-model="recordToAdd"
></v-overflow-btn>
<p v-if =" recordToAdd === '1' ">A's content is here -- i.e, Option A must be disabled in selection option</p>
</v-container>
</v-app>
</div>
JS
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
recordToAdd : "",
items: [
{text:"A",value:"1"},
{text:"B",value:"2"},
{text:"C",value:"3"},
],
}),
})
You just need to add disabled: true in the data.
<template>
...
<v-overflow-btn
class="my-2"
:items="dropdown"
label="Test"
segmented
target="#dropdown-example"
/>
...
</template>
...
data() {
return {
disabled: false,
dropdown: [
// Always disabled
{ text: 'disabled option', callback: () => console.log('disabled'), disabled: true },
// disable depending on another variable
{ text: 'depending', callback: () => console.log('Hello'), disabled: this.disabled },
{ text: 'other Option', callback: () => console.log('Option') },
]
}
},