Vuetify Combobox 添加新项目作为对象而不是字符串
Vuetify Combobox add new item as object instead of string
我正在使用 Vuetify(v2.6.3)
构建一个 new/edit 项目表单。我的表单有多个组合框,它们将它们的项目从后端 API 作为对象拉出。我希望能够添加组合框能够做到的新项目。但是,当我添加新项目时,它会作为字符串添加。有没有办法将该新项目添加为对象?
我只需要新对象有一个name
键,以便将它发送到API待创建
想要 New
项来自 v-combobox
:
{
name: 'New Item',
}
从 API 返回并可作为组合框选项的简化项目列表:
[
{
id: 1,
name: 'Item 1',
createdAt: '2020-01-01',
updatedAt: '2020-01-01'
},
{
id: 2,
name: 'Item 2',
createdAt: '2020-01-01',
updatedAt: '2020-01-01'
},
{
id: 3,
name: 'Item 3',
createdAt: '2020-01-01',
updatedAt: '2020-01-01'
}
]
这是我的表格的简化版本:
<template>
<v-card>
<v-card-title>
<span class="text-h5">Edit Item</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col>
<v-combobox
v-model="item"
:items="items"
item-text="name"
item-value="id"
label="ComboBox"
return-object
></v-combobox>
</v-col>
</v-row>
</v-container>
</v-card-text>
</v-card>
</template>
<script>
export default {
name: 'TestForm',
data() {
return {
item: null,
items: [
{
id: 1,
name: 'Item 1',
createdAt: '2020-01-01',
updatedAt: '2020-01-01',
},
{
id: 2,
name: 'Item 2',
createdAt: '2020-01-01',
updatedAt: '2020-01-01',
},
{
id: 3,
name: 'Item 3',
createdAt: '2020-01-01',
updatedAt: '2020-01-01',
},
],
}
},
}
</script>
在我将表单发送到 API 的方法中,我可以检查每个组合框的值并在需要时转换为一个对象,但我想知道是否可以在组合框组件中处理它.
似乎ComboBox在添加新项时不能直接return一个对象。但是,看起来您可以利用组件的 input
事件来 运行 一个转换为对象的方法。
下面是我如何调用组件的 input
事件的方法:
<v-combobox
v-model="item"
:items="items"
item-text="name"
item-value="id"
label="ComboBox"
return-object
@input="makeObject"
></v-combobox>
@input="makeObject"
监听组件的input
事件并调用makeObject
方法并传递当前选中的item
然后我能够编写一个方法来检查组合框值是否为字符串。如果是,则将其转换为对象
<script>
export default {
name: "TestForm",
data() {
return {
item: null
// Remaining code omitted for readability
}
}
methods: {
makeObject(val) {
if (typeof val === "string") {
this.item = {
name: val,
};
}
},
},
};
</script>
这是我的完整组件:
<template>
<v-card>
<v-card-title>
<span class="text-h5">Edit Item</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col>
<v-combobox
v-model="item"
:items="items"
item-text="name"
item-value="id"
label="ComboBox"
return-object
@input="makeObject"
></v-combobox>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-text>
{{ item }}
</v-card-text>
</v-card>
</template>
<script>
export default {
name: "TestForm",
data() {
return {
item: null,
items: [
{
id: 1,
name: "Item 1",
createdAt: "2020-01-01",
updatedAt: "2020-01-01",
},
{
id: 2,
name: "Item 2",
createdAt: "2020-01-01",
updatedAt: "2020-01-01",
},
{
id: 3,
name: "Item 3",
createdAt: "2020-01-01",
updatedAt: "2020-01-01",
},
],
};
},
methods: {
makeObject(val) {
if (typeof val === "string") {
this.item = {
name: val,
};
}
},
},
};
</script>
VComboBox
似乎不支持这一点,但您可以通过使用 component's change
-event 来解决它,如果需要的话添加一个带有条目的新对象:
在 v-combobox
.
上添加一个 change
事件处理程序(例如,命名为 onChange
)
在onChange()
中,通过name
查找items
中的条目(即对应于VComboBox
的item-text
支柱).
如果找到,将 item
设置为现有项目。
否则,使用该条目创建一个新对象,并将 item
设置为新创建的对象。请注意,新对象的 id
(即对应于 VComboBox
的 item-value
属性)必须是唯一的,VComboBox
才能创建和跟踪它。
<v-combobox
v-model="item"
@change="onChange" 1️⃣
/>
let nextId = 1
export default {
⋮
methods: {
addItem(name) {
const newItem = {
id: nextId++,
name,
}
this.items.push(newItem)
return newItem
},
1️⃣
onChange(entry) {
if (typeof entry === 'string' && entry.trim()) {
2️⃣
const item = this.items.find(item => item.name === entry)
if (item) {
3️⃣
this.item = item
} else {
4️⃣
this.item = this.addItem(entry)
}
}
},
},
}
我发现接受的答案很有用,但这里有一个类似的解决方案,允许使用芯片的多个 selection 组合框。我用它来实现用户 select 多个“标签”的方法:
例如。 Stackblitz runnable example
<v-combobox
v-model="selectedItems"
:items="items"
chips
clearable
multiple
@change="OnChange"
item-text="TagName"
item-value="TagId"
label="Categories"
solo
prepend-icon="mdi-tag-multiple"
return-object>
<template v-slot:selection="{ attrs, item, select, selected }">
<v-chip
v-bind="attrs"
:input-value="selected"
color="primary"
close
@click="select"
@click:close="RemoveTag(item)"
>
<span>{{ item.TagName }}</span>
</v-chip>
</template>
</v-combobox>
这是处理这些标签的 Add/Removal 的代码:
private OnChange(tags: any) {
let tagsArray = tags as [];
tagsArray.forEach(function(tag: any) {
// New tags are added as type "string" so we need to convert this to a Tag
// Iterate through the selected Tags and for each "string" found convert it to a Tag
if (typeof tag === 'string' && tag.trim()) {
const item = this.selectedItems.find(item => item === tag);
if (item) {
let newTag = new Tag(0, tag);
// Remove the string based tag
const index = this.selectedItems.indexOf(tag, 0);
if (index > -1) {
this.selectedItems.splice(index, 1);
}
// Add a new tag object instead
this.selectedItems.push(newTag);
return;
}
}
}.bind(this))
}
private RemoveTag(tagToRemove: Tag) {
var indexOfItemToRemove = this.selectedItems.findIndex(x => x.TagName == tagToRemove.TagName);
this.selectedItems.splice(indexOfItemToRemove, 1);
}
我正在使用 Vuetify(v2.6.3)
构建一个 new/edit 项目表单。我的表单有多个组合框,它们将它们的项目从后端 API 作为对象拉出。我希望能够添加组合框能够做到的新项目。但是,当我添加新项目时,它会作为字符串添加。有没有办法将该新项目添加为对象?
我只需要新对象有一个name
键,以便将它发送到API待创建
想要 New
项来自 v-combobox
:
{
name: 'New Item',
}
从 API 返回并可作为组合框选项的简化项目列表:
[
{
id: 1,
name: 'Item 1',
createdAt: '2020-01-01',
updatedAt: '2020-01-01'
},
{
id: 2,
name: 'Item 2',
createdAt: '2020-01-01',
updatedAt: '2020-01-01'
},
{
id: 3,
name: 'Item 3',
createdAt: '2020-01-01',
updatedAt: '2020-01-01'
}
]
这是我的表格的简化版本:
<template>
<v-card>
<v-card-title>
<span class="text-h5">Edit Item</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col>
<v-combobox
v-model="item"
:items="items"
item-text="name"
item-value="id"
label="ComboBox"
return-object
></v-combobox>
</v-col>
</v-row>
</v-container>
</v-card-text>
</v-card>
</template>
<script>
export default {
name: 'TestForm',
data() {
return {
item: null,
items: [
{
id: 1,
name: 'Item 1',
createdAt: '2020-01-01',
updatedAt: '2020-01-01',
},
{
id: 2,
name: 'Item 2',
createdAt: '2020-01-01',
updatedAt: '2020-01-01',
},
{
id: 3,
name: 'Item 3',
createdAt: '2020-01-01',
updatedAt: '2020-01-01',
},
],
}
},
}
</script>
在我将表单发送到 API 的方法中,我可以检查每个组合框的值并在需要时转换为一个对象,但我想知道是否可以在组合框组件中处理它.
似乎ComboBox在添加新项时不能直接return一个对象。但是,看起来您可以利用组件的 input
事件来 运行 一个转换为对象的方法。
下面是我如何调用组件的 input
事件的方法:
<v-combobox
v-model="item"
:items="items"
item-text="name"
item-value="id"
label="ComboBox"
return-object
@input="makeObject"
></v-combobox>
@input="makeObject"
监听组件的input
事件并调用makeObject
方法并传递当前选中的item
然后我能够编写一个方法来检查组合框值是否为字符串。如果是,则将其转换为对象
<script>
export default {
name: "TestForm",
data() {
return {
item: null
// Remaining code omitted for readability
}
}
methods: {
makeObject(val) {
if (typeof val === "string") {
this.item = {
name: val,
};
}
},
},
};
</script>
这是我的完整组件:
<template>
<v-card>
<v-card-title>
<span class="text-h5">Edit Item</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col>
<v-combobox
v-model="item"
:items="items"
item-text="name"
item-value="id"
label="ComboBox"
return-object
@input="makeObject"
></v-combobox>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-text>
{{ item }}
</v-card-text>
</v-card>
</template>
<script>
export default {
name: "TestForm",
data() {
return {
item: null,
items: [
{
id: 1,
name: "Item 1",
createdAt: "2020-01-01",
updatedAt: "2020-01-01",
},
{
id: 2,
name: "Item 2",
createdAt: "2020-01-01",
updatedAt: "2020-01-01",
},
{
id: 3,
name: "Item 3",
createdAt: "2020-01-01",
updatedAt: "2020-01-01",
},
],
};
},
methods: {
makeObject(val) {
if (typeof val === "string") {
this.item = {
name: val,
};
}
},
},
};
</script>
VComboBox
似乎不支持这一点,但您可以通过使用 component's change
-event 来解决它,如果需要的话添加一个带有条目的新对象:
在
上添加一个v-combobox
.change
事件处理程序(例如,命名为onChange
)在
onChange()
中,通过name
查找items
中的条目(即对应于VComboBox
的item-text
支柱).如果找到,将
item
设置为现有项目。否则,使用该条目创建一个新对象,并将
item
设置为新创建的对象。请注意,新对象的id
(即对应于VComboBox
的item-value
属性)必须是唯一的,VComboBox
才能创建和跟踪它。
<v-combobox
v-model="item"
@change="onChange" 1️⃣
/>
let nextId = 1
export default {
⋮
methods: {
addItem(name) {
const newItem = {
id: nextId++,
name,
}
this.items.push(newItem)
return newItem
},
1️⃣
onChange(entry) {
if (typeof entry === 'string' && entry.trim()) {
2️⃣
const item = this.items.find(item => item.name === entry)
if (item) {
3️⃣
this.item = item
} else {
4️⃣
this.item = this.addItem(entry)
}
}
},
},
}
我发现接受的答案很有用,但这里有一个类似的解决方案,允许使用芯片的多个 selection 组合框。我用它来实现用户 select 多个“标签”的方法:
例如。 Stackblitz runnable example
<v-combobox
v-model="selectedItems"
:items="items"
chips
clearable
multiple
@change="OnChange"
item-text="TagName"
item-value="TagId"
label="Categories"
solo
prepend-icon="mdi-tag-multiple"
return-object>
<template v-slot:selection="{ attrs, item, select, selected }">
<v-chip
v-bind="attrs"
:input-value="selected"
color="primary"
close
@click="select"
@click:close="RemoveTag(item)"
>
<span>{{ item.TagName }}</span>
</v-chip>
</template>
</v-combobox>
这是处理这些标签的 Add/Removal 的代码:
private OnChange(tags: any) {
let tagsArray = tags as [];
tagsArray.forEach(function(tag: any) {
// New tags are added as type "string" so we need to convert this to a Tag
// Iterate through the selected Tags and for each "string" found convert it to a Tag
if (typeof tag === 'string' && tag.trim()) {
const item = this.selectedItems.find(item => item === tag);
if (item) {
let newTag = new Tag(0, tag);
// Remove the string based tag
const index = this.selectedItems.indexOf(tag, 0);
if (index > -1) {
this.selectedItems.splice(index, 1);
}
// Add a new tag object instead
this.selectedItems.push(newTag);
return;
}
}
}.bind(this))
}
private RemoveTag(tagToRemove: Tag) {
var indexOfItemToRemove = this.selectedItems.findIndex(x => x.TagName == tagToRemove.TagName);
this.selectedItems.splice(indexOfItemToRemove, 1);
}