如何将 Vuelidate 与可编辑的 Vuetify 数据 Table 字段一起使用
How to use Vuelidate with editable Vuetify Data Table field
我想将 Vuelidate 验证添加到 Vuetify 数据 table 中的 editable 字段。但是,我不知道如何使用 props.item 参数使其工作。
对于正常的输入字段,我会做类似的事情
:error-messages="qtyErrors"
@input="$v.quantity.$touch()"
@blur="$v.quantity.$touch()"
.
.
validations: {
quantity: { required, numeric }
}
我不知道如何为 props.item.squareFootage 制作此作品。我不确定如何处理索引。这是我的数据 table。如有任何建议,我们将不胜感激。
<v-data-table
:headers="bldgHeaders"
:items="selectedBldgs"
:pagination.sync="paginationSelected"
class="elevation-1"
>
<template slot="items" slot-scope="props">
<tr>
<td>{{ props.item.buildingNumber }}</td>
<td>{{ props.item.description }}</td>
<td>
<v-edit-dialog
:return-value.sync="props.item.squareFootage"
lazy
large
> {{ props.item.squareFootage }}
<v-text-field
slot="input"
v-model="props.item.squareFootage"
label="Edit"
single-line
></v-text-field>
</v-edit-dialog>
</td>
</tr>
</template>
您不想为数据中的每一行呈现一个对话框table。在页面上呈现一个对话框并跟踪用户正在编辑数据 属性 中的哪一行。此 属性 在以下代码段中称为 "currentItem"。然后,您可以将验证绑定到仅那个对象中的属性,而不是为 table 中的每一行创建验证。如果你不想使用 v-dialog 你也可以使用 v-menu positioned absolutely without an external activator.
const {
required,
maxLength,
email
} = validators
const validationMixin = vuelidate.validationMixin
Vue.use(vuelidate.default)
new Vue({
el: '#app',
data() {
return {
editDialog: false,
currentItem: {},
headers: [{
text: 'Dessert (100g serving)',
align: 'left',
sortable: false,
value: 'name'
},
{
text: 'Calories',
value: 'calories'
},
{
text: 'Fat (g)',
value: 'fat'
}
],
desserts: [{
id: 1,
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0
},
{
id: 2,
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0
}
]
}
},
validations: {
currentItem: {
fat: {
required
}
}
},
methods: {
openEditDialog(item) {
this.currentItem = Object.assign({}, item)
this.editDialog = true
},
validate() {
this.$v.currentItem.fat.$touch()
if (!this.$v.currentItem.fat.$error) this.editDialog = false
}
}
})
<script src="https://unpkg.com/vuelidate/dist/validators.min.js"></script>
<script src="https://unpkg.com/vuelidate/dist/vuelidate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!DOCTYPE html>
<html>
<head>
<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">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
</head>
<body>
<div id="app">
<v-app>
<v-content>
<v-container>
<v-data-table :headers="headers" :items="desserts" class="elevation-1">
<template slot="items" slot-scope="props">
<tr @click="openEditDialog(props.item)">
<td>{{ props.item.name }}</td>
<td class="text-xs-center">{{ props.item.calories }}</td>
<td class="text-xs-center">{{ props.item.fat }}</td>
</tr>
</template>
</v-data-table>
</v-container>
<v-dialog v-model="editDialog" width="500">
<v-card>
<v-card-title class="headline grey lighten-2" primary-title>
Set Fat Content
</v-card-title>
<v-card-text>
<v-form>
<v-text-field label="Fat" v-model="currentItem.fat" required :error="$v.currentItem.fat.$dirty && $v.currentItem.fat.$error">
</v-text-field>
</v-form>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" flat @click="validate()">
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-content>
</v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
</body>
</html>
vuelidate 库支持使用 $iter 关键字的 Collection。您只需要在 $iter 关键字下声明项目的数据结构,vuelidate 将为每个项目构建验证对象。例如,您可以在此处查看 https://vuelidate.js.org/#sub-collections-validation.
但是,问题发生在访问 v-data-table 的行模板中的这些验证对象时。由于生成的验证对象只能由迭代器访问,它不是一个列表,行模板中的代码需要一种方法来访问这些验证对象。在这里,我使用了两个辅助函数:getV() 用于访问验证对象和 getVModel() 验证对象的数据模型。
getIter () {
return Object.values(this.$v.items.$each.$iter)
},
getV (item) {
if (!item.vLink) item.vLink = this.getIter().filter(i => i.$model.Id === item.Id)[0]
return item.vLink
},
getVModel (item) {
return this.getV(item).$model
},
然后在vue的模板中,行模板的:class可以使用getV()来访问$invalid或$dirty,行模板的v-model可以使用getVModel()来访问数据。
示例如下:
v-data-table(:headers="headers" :items="items" item-key="Id")
template(v-slot:body="{ items }")
tbody
tr(v-for="item in items" :key="item.Id" :class="{ vmodified: !getV(item).$invalid && getV(item).$dirty, verror: getV(item).$invalid }")
td
input.table-input(type='text' v-model="getVModel(item).Vendor" @input="onChangeItem(getV(item))")
td
input.table-input(type='text' v-model="getVModel(item).Material" @input="onChangeItem(getV(item))")
我想将 Vuelidate 验证添加到 Vuetify 数据 table 中的 editable 字段。但是,我不知道如何使用 props.item 参数使其工作。
对于正常的输入字段,我会做类似的事情
:error-messages="qtyErrors"
@input="$v.quantity.$touch()"
@blur="$v.quantity.$touch()"
.
.
validations: {
quantity: { required, numeric }
}
我不知道如何为 props.item.squareFootage 制作此作品。我不确定如何处理索引。这是我的数据 table。如有任何建议,我们将不胜感激。
<v-data-table
:headers="bldgHeaders"
:items="selectedBldgs"
:pagination.sync="paginationSelected"
class="elevation-1"
>
<template slot="items" slot-scope="props">
<tr>
<td>{{ props.item.buildingNumber }}</td>
<td>{{ props.item.description }}</td>
<td>
<v-edit-dialog
:return-value.sync="props.item.squareFootage"
lazy
large
> {{ props.item.squareFootage }}
<v-text-field
slot="input"
v-model="props.item.squareFootage"
label="Edit"
single-line
></v-text-field>
</v-edit-dialog>
</td>
</tr>
</template>
您不想为数据中的每一行呈现一个对话框table。在页面上呈现一个对话框并跟踪用户正在编辑数据 属性 中的哪一行。此 属性 在以下代码段中称为 "currentItem"。然后,您可以将验证绑定到仅那个对象中的属性,而不是为 table 中的每一行创建验证。如果你不想使用 v-dialog 你也可以使用 v-menu positioned absolutely without an external activator.
const {
required,
maxLength,
email
} = validators
const validationMixin = vuelidate.validationMixin
Vue.use(vuelidate.default)
new Vue({
el: '#app',
data() {
return {
editDialog: false,
currentItem: {},
headers: [{
text: 'Dessert (100g serving)',
align: 'left',
sortable: false,
value: 'name'
},
{
text: 'Calories',
value: 'calories'
},
{
text: 'Fat (g)',
value: 'fat'
}
],
desserts: [{
id: 1,
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0
},
{
id: 2,
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0
}
]
}
},
validations: {
currentItem: {
fat: {
required
}
}
},
methods: {
openEditDialog(item) {
this.currentItem = Object.assign({}, item)
this.editDialog = true
},
validate() {
this.$v.currentItem.fat.$touch()
if (!this.$v.currentItem.fat.$error) this.editDialog = false
}
}
})
<script src="https://unpkg.com/vuelidate/dist/validators.min.js"></script>
<script src="https://unpkg.com/vuelidate/dist/vuelidate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!DOCTYPE html>
<html>
<head>
<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">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
</head>
<body>
<div id="app">
<v-app>
<v-content>
<v-container>
<v-data-table :headers="headers" :items="desserts" class="elevation-1">
<template slot="items" slot-scope="props">
<tr @click="openEditDialog(props.item)">
<td>{{ props.item.name }}</td>
<td class="text-xs-center">{{ props.item.calories }}</td>
<td class="text-xs-center">{{ props.item.fat }}</td>
</tr>
</template>
</v-data-table>
</v-container>
<v-dialog v-model="editDialog" width="500">
<v-card>
<v-card-title class="headline grey lighten-2" primary-title>
Set Fat Content
</v-card-title>
<v-card-text>
<v-form>
<v-text-field label="Fat" v-model="currentItem.fat" required :error="$v.currentItem.fat.$dirty && $v.currentItem.fat.$error">
</v-text-field>
</v-form>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" flat @click="validate()">
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-content>
</v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
</body>
</html>
vuelidate 库支持使用 $iter 关键字的 Collection。您只需要在 $iter 关键字下声明项目的数据结构,vuelidate 将为每个项目构建验证对象。例如,您可以在此处查看 https://vuelidate.js.org/#sub-collections-validation.
但是,问题发生在访问 v-data-table 的行模板中的这些验证对象时。由于生成的验证对象只能由迭代器访问,它不是一个列表,行模板中的代码需要一种方法来访问这些验证对象。在这里,我使用了两个辅助函数:getV() 用于访问验证对象和 getVModel() 验证对象的数据模型。
getIter () {
return Object.values(this.$v.items.$each.$iter)
},
getV (item) {
if (!item.vLink) item.vLink = this.getIter().filter(i => i.$model.Id === item.Id)[0]
return item.vLink
},
getVModel (item) {
return this.getV(item).$model
},
然后在vue的模板中,行模板的:class可以使用getV()来访问$invalid或$dirty,行模板的v-model可以使用getVModel()来访问数据。
示例如下:
v-data-table(:headers="headers" :items="items" item-key="Id")
template(v-slot:body="{ items }")
tbody
tr(v-for="item in items" :key="item.Id" :class="{ vmodified: !getV(item).$invalid && getV(item).$dirty, verror: getV(item).$invalid }")
td
input.table-input(type='text' v-model="getVModel(item).Vendor" @input="onChangeItem(getV(item))")
td
input.table-input(type='text' v-model="getVModel(item).Material" @input="onChangeItem(getV(item))")