【问题标题】:Vuetify Combobox add new item as object instead of stringVuetify Combobox 添加新项目作为对象而不是字符串
【发布时间】:2022-02-28 05:20:24
【问题描述】:

我正在使用Vuetify(v2.6.3) 构建一个新的/编辑项目表单。我的表单有多个组合框,它们从后端 API 中提取它们的项目作为对象。我希望能够添加组合框能够执行的新项目。但是,当我添加一个新项目时,它会作为字符串添加。有没有办法将新项目添加为对象?

我只需要新对象有一个name 密钥,以便将其发送到要创建的 API

来自v-combobox 的所需New 项目:

{
  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 的方法中,我可以检查每个组合框的值并在需要时转换为对象,但我想知道是否可以在组合框组件中处理它。

【问题讨论】:

    标签: node.js vue.js nuxt.js vuetify.js


    【解决方案1】:

    VComboBox 似乎不支持这一点,但如果需要,您可以使用component's change-event 添加一个带有条目的新对象来解决它:

    1. v-combobox 上添加一个change-事件处理程序(例如,命名为onChange)。

    2. onChange() 中,通过name 查找items 中的条目(即,对应于VComboBoxitem-text 属性)。

    3. 如果找到,请将item 设置为现有项目。

    4. 否则,使用该条目创建一个新对象,并将item 设置为新创建的对象。请注意,新对象的 id(即,对应于 VComboBoxitem-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)
            }
          }
        },
      },
    }
    

    demo

    【讨论】:

      【解决方案2】:

      我发现接受的答案很有用,但这里有一个类似的解决方案,它允许使用筹码进行多选组合框。我用它来实现一种让用户选择多个“标签”的方法:

      例如。 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>
      

      以下是处理这些标签的添加/删除的代码:

      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);
      }
      

      【讨论】:

        【解决方案3】:

        似乎 ComboBox 在添加新项目时不能直接返回对象。但是,您似乎可以利用组件的 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 方法并传递当前选中的项

        然后我可以编写一个方法来检查组合框的值是否为字符串。如果是,则将其转换为对象

        <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>
        

        sandbox link

        【讨论】:

          猜你喜欢
          • 2018-03-18
          • 1970-01-01
          • 1970-01-01
          • 2013-02-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多