Проблема в запросах POST и PUT, с топором ios, vuetify datatable, vuejs - PullRequest
1 голос
/ 23 апреля 2020

Я пытаюсь адаптировать образец данных с самого сайта vuetify в соответствии с моими потребностями, используя ax ios для использования моего API. Метод 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-width="600px">
            <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>

При открытии модального окна для добавления элемента, только при открытии выбора и изменении жанра эта ошибка уже появляется перед сохранением, как показано на рисунке:

При нажатии на кнопку сохранения она сохраняется только спереди, а при обновлении страницы запись исчезает, может кто-нибудь подсказать мне?

Обновить правку.

После некоторые изменения, я думаю, что я ближе к решению, но я столкнулся со следующим препятствием: при сохранении клиентского элемента пол сохраняется пустым.

image файла 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-width="600px">
            <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 Ответ

1 голос
/ 23 апреля 2020

Есть пара вопросов. Во-первых, вы не передаете никаких данных вашим запросам PUT и POST. Они должны выглядеть примерно так:

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 { /* ... */ }
},

Во-вторых, под капотом <v-select> использует v-for для перебора всех опций, которые должны go в раскрывающемся меню. Если бы это был простой элемент HTML <select>, он бы выглядел примерно так:

<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 ожидает, что массив родов будет в одном из двух форматов, либо массив строк, либо массив объектов со свойствами text и value:

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, какие свойства использовать для value и свойства text (это выглядит так, как вы). Так что, если ваш массив genders выглядит следующим образом:

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

Ваш <v-select> должен выглядеть следующим образом (в вашем случае вы использовали свойство SAME для текста и значения, что прекрасно подходит для этого):

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

Я предполагаю, основываясь на прикрепленном изображении, что массив genders НЕ в одном из этих форматов, и это вызывает ошибку, когда Vuetify пытается превратить его в падать. Кроме того, я думаю, что вы намерены присвоить выбранное значение editedItem.gender, а не editedItem.gender.name. Вот кодовая ручка, показывающая, как использовать объекты для v-select элементов .

Если массив items имеет один из двух форматов, которые я показал ранее, вам НЕ нужно указывать item-text и item-value реквизит. Они будут обнаружены автоматически.

Надеюсь, это поможет!

...