POST 和 PUT 请求中的问题,使用 axios、vuetify 数据表、vuejs

Posted

技术标签:

【中文标题】POST 和 PUT 请求中的问题,使用 axios、vuetify 数据表、vuejs【英文标题】:Problem in POST and PUT request, with axios, vuetify datatable, vuejs 【发布时间】:2020-08-07 03:03:42 【问题描述】:

我正在尝试根据我的需要通过实施 axios 来使用我的 api 来调整 vuetify 网站本身的示例数据表。 GET AND DELETE 方法运行良好,但是我对 POST AND PUT 方法很困惑,我使用 2 个模型作为客户端以及与类型的关系,跟随部分代码:

<template>
    <v-data-table
      :headers="headers"
      :items="clients"
      sort-by="firstName"
      class="elevation-2"
    >
      <template v-slot:top>
        <v-toolbar flat color="white">
          <v-icon medium>mdi-account-supervisor</v-icon>
            <v-toolbar-title> Clients</v-toolbar-title>
          <v-divider
            class="mx-4"
            inset
            vertical
          ></v-divider>
          <v-spacer></v-spacer>
          <v-dialog v-model="dialog" max->
            <template v-slot:activator=" on ">
                <v-btn 
                color="blue" 
                dark class="mt-6 mb-4" 
                v-on="on"
                rounded
                ><v-icon medium>mdi-plus</v-icon>Add new</v-btn>
            </template>
            <v-card>
              <v-card-title>
                <span class="headline"> formTitle </span>
              </v-card-title>

              <v-card-text>
                <v-container>
                  <v-form>
                    <v-row>
                      <v-col cols="12" sm="6" md="12">
                        <v-text-field v-model="editedItem.firstName" label="First Name"></v-text-field>
                      </v-col>
                      <v-col cols="12" sm="6" md="12">
                        <v-text-field v-model="editedItem.lastName" label="Last Name"></v-text-field>
                      </v-col>
                      <v-col cols="12" sm="6" md="12">
                        <v-text-field v-model="editedItem.email" label="E-Mail"></v-text-field>
                      </v-col>
                      <v-col cols="12" sm="6" md="12">
                        <v-text-field v-model="editedItem.phone" label="Phone"></v-text-field>
                      </v-col>
                      <v-col cols="12" sm="6" md="12">
                        <v-text-field v-model="editedItem.mobilePhone" label="Mobile Phone"></v-text-field>
                      </v-col>
                      <v-col cols="12" sm="6" md="12">
                        <!-- select options-->
                        <v-select
                          label='Gender'
                          v-model='editedItem.gender.name'
                          :items='genders'
                          item-value='name'
                          item-text='name'
                        >
                        </v-select>
                      </v-col>
                    </v-row>
                  </v-form>
                </v-container>
              </v-card-text>

              <v-card-actions>
                <v-spacer></v-spacer>
                <v-btn color="error" rounded @click="close">Cancel</v-btn>
                <v-btn color="primary" rounded @click="save">Save</v-btn>
              </v-card-actions>
            </v-card>
          </v-dialog>
        </v-toolbar>
      </template>
      <template v-slot:item.action=" item ">
        <v-icon
          small
          color="green"
          class="mr-2"
          @click="editItem(item)"
        >
          mdi-pencil
        </v-icon>
        <v-icon
          small
          color="red"
          @click="deleteItem(item)"
        >
          mdi-delete
        </v-icon>

      </template>
      <template v-slot:no-data>
        <v-btn color="primary" @click="initialize">Reset</v-btn>
      </template>
    </v-data-table>
</template>

<script>
import axios from 'axios'
import Client from '../../services/clients';
import Gender from '../../services/genders';

  export default 
    data: () => (
      dialog: false,
      headers: [
        
          text: 'First Name',
          align: 'start',
          sortable: false,
          value: 'firstName',
        ,
         text: 'Last Name', value: 'lastName' ,
         text: 'Email', value: 'email' ,
         text: 'Phone', value: 'phone' ,
         text: 'Mobile Phone', value: 'mobilePhone' ,
         text: 'Gender', value: 'gender.name' ,
         text: 'Actions', value: 'action', sortable: false ,
      ],
      clients: [],
      genders: [],
      errors: [],
      editedIndex: -1,
      editedItem: 
        firstName: '',
        lastName: '',
        email: '',
        phone: '',
        mobilePhone: '',
        gender: '',
      ,
      defaultItem: 
        firstName: '',
        lastName: '',
        email: '',
        phone: '',
        mobilePhone: '',
        gender: '',
      ,
    ),
    computed: 
      formTitle () 
        return this.editedIndex === -1 ? 'New Item' : 'Edit Item'
      ,
    ,
    watch: 
      dialog (val) 
        val || this.close()
      ,
    ,
    created () 
      this.initialize()
    ,
    methods: 
      initialize () 
        Client.list().then(response => 
          this.clients = response.data
        ).catch(e => 
          console.log(e)
        );
        Gender.list().then(response => 
          this.genders = response.data
        ).catch(e => 
          console.log(e)
        );

      ,
      editItem (item) 
        axios.put('http://192.168.26.130:3000/client/' + item.id)
          .then(response => 
            this.editedIndex = this.clients.indexOf(item)
            this.editedItem = Object.assign(, item)
            this.editedID = this.editedItem.id
            this.dialog = true
            this.response = response
        ).catch(e => 
          console.log(e)
        );
      ,

      deleteItem (item) 
        if (confirm("Do you really want to delete?")) 
          axios.delete('http://192.168.26.130:3000/client/' + item.id)
          .then(response => 
            const index = this.clients.indexOf(item)
            this.deletedItem = Object.assign(, item)
            this.deletedID = this.deletedItem.id
            this.clients.splice(index, 1);
            this.response = response
          ).catch(e => 
          console.log(e)
        );
        
      ,

      close () 
        this.dialog = false
        setTimeout(() => 
          this.editedItem = Object.assign(, this.defaultItem)
          this.editedIndex = -1
        , 300)
      ,

      save () 
        if (this.editedIndex > -1) 
          axios.post('http://192.168.26.130:3000/client/')
          .then(response => 
            Object.assign(this.clients[this.editedIndex], this.editedItem)
            this.response = response.data
          ).catch(e => 
          console.log(e)
        );
         else 
            this.clients.push(this.editedItem)
        
        this.close()
      ,

    ,
  
</script>

在打开modal添加item时,只有在打开select和修改genre的时候,在保存之前就已经出现了这个错误,如图:

点击保存时只保存在最前面,更新页面时记录消失,谁能给我指点一下?

更新编辑。

经过一些更改,我认为我更接近解决方案,但我遇到了以下障碍,保存客户端项目时,性别存储为空。

的console.log和前端保存的项目但在数据库中性别为空

DataTable.vue 文件:

<template>
    <v-data-table
      :headers="headers"
      :items="clients"
      sort-by="firstName"
      class="elevation-2"
    >
      <template v-slot:top>
        <v-toolbar flat color="white">
          <v-icon medium>mdi-account-supervisor</v-icon>
            <v-toolbar-title> Clients</v-toolbar-title>
          <v-divider
            class="mx-4"
            inset
            vertical
          ></v-divider>
          <v-spacer></v-spacer>
          <v-dialog v-model="dialog" max->
            <template v-slot:activator=" on ">
                <v-btn 
                color="blue" 
                dark class="mt-6 mb-4" 
                v-on="on"
                rounded
                ><v-icon medium>mdi-plus</v-icon>Add new</v-btn>
            </template>
            <v-card>
              <v-card-title>
                <span class="headline"> formTitle </span>
              </v-card-title>

              <v-card-text>
                <v-container>
                  <v-form>
                    <v-row>
                      <v-col cols="12" sm="6" md="12">
                        <v-text-field v-model="editedItem.firstName" label="First Name"></v-text-field>
                      </v-col>
                      <v-col cols="12" sm="6" md="12">
                        <v-text-field v-model="editedItem.lastName" label="Last Name"></v-text-field>
                      </v-col>
                      <v-col cols="12" sm="6" md="12">
                        <v-text-field v-model="editedItem.email" label="E-Mail"></v-text-field>
                      </v-col>
                      <v-col cols="12" sm="6" md="12">
                        <v-text-field v-model="editedItem.phone" label="Phone"></v-text-field>
                      </v-col>
                      <v-col cols="12" sm="6" md="12">
                        <v-text-field v-model="editedItem.mobilePhone" label="Mobile Phone"></v-text-field>
                      </v-col>
                      <v-col cols="12" sm="6" md="12">
                        <!-- select options-->
                        <v-select
                          label='Gender'
                          v-model='editedItem.gender'
                          :items='genders'
                          item-value='name'
                          item-text='name'
                        >
                        </v-select>
                      </v-col>
                    </v-row>
                  </v-form>
                </v-container>
              </v-card-text>

              <v-card-actions>
                <v-spacer></v-spacer>
                <v-btn color="error" rounded @click="close">Cancel</v-btn>
                <v-btn color="primary" rounded @click="save">Save</v-btn>
              </v-card-actions>
            </v-card>
          </v-dialog>
        </v-toolbar>
      </template>
      <template v-slot:item.action=" item ">
        <v-icon
          small
          color="green"
          class="mr-2"
          @click="editItem(item)"
        >
          mdi-pencil
        </v-icon>
        <v-icon
          small
          color="red"
          @click="deleteItem(item)"
        >
          mdi-delete
        </v-icon>

      </template>
      <template v-slot:no-data>
        <v-btn color="primary" @click="initialize">Reset</v-btn>
      </template>
    </v-data-table>
</template>

<script>
import axios from 'axios'
import Client from '../../services/clients';
import Gender from '../../services/genders';

  export default 
    data: () => (
      dialog: false,
      headers: [
        
          text: 'First Name',
          align: 'start',
          sortable: false,
          value: 'firstName',
        ,
         text: 'Last Name', value: 'lastName' ,
         text: 'Email', value: 'email' ,
         text: 'Phone', value: 'phone' ,
         text: 'Mobile Phone', value: 'mobilePhone' ,
         text: 'Gender', value: 'gender.name' ,
         text: 'Actions', value: 'action', sortable: false ,
      ],
      clients: [],
      genders: [],
      errors: [],
      editedIndex: -1,
      editedItem: 
        firstName: '',
        lastName: '',
        email: '',
        phone: '',
        mobilePhone: '',
        gender: '',
      ,
      defaultItem: 
        firstName: '',
        lastName: '',
        email: '',
        phone: '',
        mobilePhone: '',
        gender: '',
      ,
    ),
    computed: 
      formTitle () 
        return this.editedIndex === -1 ? 'New Item' : 'Edit Item'
      ,
    ,
    watch: 
      dialog (val) 
        val || this.close()
      ,
    ,
    created () 
      this.initialize()
    ,
    methods: 
      initialize () 
        Client.list().then(response => 
          this.clients = response.data
        ).catch(e => 
          console.log(e)
        );
        Gender.list().then(response => 
          this.genders = response.data
        ).catch(e => 
          console.log(e)
        );

      ,
      editItem (item) 
        axios.put('http://192.168.26.130:3000/client/' + item.id)
          .then(response => 
            this.editedIndex = this.clients.indexOf(item)
            this.editedItem = Object.assign(, item)
            this.editedID = this.editedItem.id
            this.dialog = true
            this.response = response
        ).catch(error => 
          console.log(error.response)
        );
      ,

      deleteItem (item) 
        if (confirm("Do you really want to delete?")) 
          axios.delete('http://192.168.26.130:3000/client/' + item.id)
            .then(response => 
              const index = this.clients.indexOf(item)
              this.deletedItem = Object.assign(, item)
              this.deletedID = this.deletedItem.id
              this.clients.splice(index, 1);
              this.response = response
            ).catch(error => 
                console.log(error.response)
              );
        
      ,

      close () 
        this.dialog = false
        setTimeout(() => 
          this.editedItem = Object.assign(, this.defaultItem)
          this.editedIndex = -1
        , 300)
      ,

      save () 
        if (this.editedIndex > -1) 
          Object.assign(this.clients[this.editedIndex], this.editedItem)
         else 
            this.clients.push(this.editedItem)
            axios.post('http://192.168.26.130:3000/client/', this.editedItem)
              .then(response => 
                console.log(response)
              ).catch(error => 
              console.log(error.response)
            );

        
        this.close()
      ,

    ,
  
</script>

请有人帮助我吗?

【问题讨论】:

【参考方案1】:

有几个问题。首先,您没有将任何数据传递给您的 PUTPOST 请求。它们应该看起来像:

editItem (item) 
  // YOU NEED TO PASS AN OBJECT TO THE PUT REQUEST         ▼▼HERE▼▼
  axios.put('http://192.168.26.130:3000/client/' + item.id , item)
    .then(response => 
      // handle response...
    )
    .catch(err =>  console.log(error) )
,
save () 
  if (this.editedIndex > -1) 
    // YOU NEED TO PASS AN OBJECT TO THE POST REQUEST  ▼▼HERE▼▼
    axios.post('http://192.168.26.130:3000/client/', this.editedItem)
      .then(response => 
        // handle response...
      )
      .catch(err =>  console.log(error) )
   else  /* ... */ 
,

其次,在底层,&lt;v-select&gt; 使用v-for 来遍历所有应该进入下拉菜单的选项。如果这是一个纯 html &lt;select&gt; 元素,它看起来像这样:

<select name="gender">
  <option value="">Select a gender...</option>
  <option
    v-for="gender in genders"
    :key="gender"
    value="gender.value"
  >
     gender.text 
  </option>
</select>

Vuetify 期望性别数组采用以下两种格式之一:字符串数组或具有textvalue 属性的对象数组:

const genders = ['male', 'female', 'other']
// OR
const genders = [
   value: 1, text: 'male' , // `value` can be anything you want
   value: 2, text: 'female' ,
   value: 3, text: 'other' ,
]

或者,如果您的 genders 数组具有不同的数据结构,您可以告诉 Vuetify 为 valuetext 属性使用哪些属性(这就是您所做的)。因此,如果您的性别数组如下所示:

const genders = [
   name: 'male' ,
   name: 'female' ,
   name: 'other' ,
]

您的 &lt;v-select&gt; 应该如下所示(在您的情况下,您对文本和值都使用了 SAME 属性,这样做非常好):

<v-select
  v-model="editedItem.gender"
  :items="genders"
  item-text="name"
  return-object
/>

根据您附加的图片,我猜测genders 数组不是这些格式之一,当 Vuetify 尝试将其转换为下拉列表时,这会导致错误。另外,我认为您打算将所选值分配给editedItem.gender 而不是editedItem.gender.name。这里是a codepen showing how to use objects for v-select items。

如果items 数组是我之前展示的两种格式之一,则不需要指定item-textitem-value 属性。它们会被自动检测到。

希望这会有所帮助!

【讨论】:

感谢您帮助澄清一些观点:流派矩阵正在从数据库中提取,现在随着更改,在保存此错误 500 Error: "Request failed with status code 500" createError createError.js: 16 settle settle.js: 17 handleLoad xhr.js: 61 DataTable.vue: 212 这意味着您创建新用户的 API 请求失败。 500 表示错误在服务器端。我的猜测是您发送到服务器的数据不是服务器期望的格式。您要么需要更改正在发送的数据结构,要么编辑服务器端以便能够接受您正在发送的结构。 我几乎得到了解决方案,现在我已经设法保存在数据库中,除了数据库中仍然为空的类型,信息必须以这种格式到达:@ 987654346@ 我相信我在这部分代码中犯了罪:defaultItem: firstName: '', lastName: '', email: '', phone: '', mobilePhone: '', gender: '', , 会是这个吗? 您是否有理由使用对象来存储性别?为什么不把它变成像名字这样的纯文本属性呢?

以上是关于POST 和 PUT 请求中的问题,使用 axios、vuetify 数据表、vuejs的主要内容,如果未能解决你的问题,请参考以下文章

Express 无法接收来自 axios put 请求的正文

Vue.js / Vuex + axios 发送多个 PUT 请求

Vue-cli webpack 设置Axios发起请求统一前缀的路径(设置统一请求地址)(发起GET请求,发起POST请求,发起PUT请求,发起DELETE请求)

API 未在 axios put 中检测 PUT 请求中的模型

CORS 正在阻止 PUT、DELETE 和 POST 请求,但 GET 正在工作

vue 对axios get pust put delete 封装