Vue.js 3:如何使用道具预填充绑定表单

Vue.js 3: how to pre-populate bound form with props

我正在尝试使用 Vuejs 3 创建一个简单的 CRUD 应用程序。

我的主页有一个表单(作为子组件)和一个 table 包含创建的项目(作为另一个子组件)。我通过表单向 API/database 和 table 更新提交数据。到目前为止一切顺利。

然后,对于更新阶段,我希望每个项目都有一个详细信息页面,我也会在其中包含表单(重复使用相同的组件)。但想法是表单字段将预先填充来自 API/Database.

的数据

主页上的 table 有一个 route-link 到详细信息页面,我将项目的 id 作为 params 传递。详细信息页面根据 id 向 API 发出请求,接收项目数据并将它们作为 props 传递到表单组件中。

如果我尝试像这样将数据直接渲染到模板中,它工作正常:

<p v-if="submitType === 'update' && item.id">{{ item.id }}</p>

现在,表单字段由 v-model 绑定到 data(例如 form.id)。但是当我尝试如下重新填充它时,我总是得到未定义的值。

  data() {
    return {
      form: {
        id: this.submitType === 'update' ? this.item.id : 0,
      }
    }
  },

我怀疑问题是对 API 的父调用是异步的并且 props 的传递被延迟了。因为当我作为 props 传递一些硬编码值时,它在表单字段中显示为一个值没有问题。此外,如果仅在收到 props 时显示表单(使用 v-if 指令),则 data.form.id 仍未定义。

那么有没有什么方法可以用接收到的 props 预填充绑定的表单字段,并且仍然让表单组件重用于插入和更新操作?其余相关代码如下。非常感谢您

// Detail Page
<template>
  <Form :item="item" submit-type="update"></Form>
</template>

<script>
export default {
  data() {
    return {
      item: {}
    }
  },
  created() {
    callAPI(id).then( response => this.item = response.data )
  }
}
</script>
// Form Component
<template>
  <p v-if="submitType === 'update' && item.id">{{ item.id }}</p>

  <div v-if="submitType === 'insert' || (submitType === 'update' && item.id )">
    <section>
      <form @submit.prevent="onSubmit">

        <div>
          <label for="id">ID</label>
          <input id="id" name="id" v-model="form.id"  type="number" placeholder="ID">
        </div>

        <input type="submit" value="Save">

      </form>
    </section>
  </div>
</template>

<script>
export default {
  name: 'Form',
  props: {
    item: {
      type: Object
    },
    submitType: {
      type: String
    }
  },
  data() {
    return {
      form: {
        id: this.submitType === 'update' ? this.item.id : 0,
      }
    }
  },
}
</script>

你可以试试watchers,看看下面的代码片段:

const app = Vue.createApp({
  data() {
    return {
      item: {},
      type: 'update'
    }
  },
  methods: {
    change() {
      this.type === 'update' ? this.type = 'insert' : this.type = 'update'
    }
  },
  created() {
    fetch('https://jsonplaceholder.typicode.com/todos/1')
      .then(response => response.json())
      .then(json => this.item = json)
    //callAPI(id).then( response => this.item = response.data )
  }
})
app.component('myForm', {
  template: `
  <p v-if="submitType === 'update' && item.id">{{ item.id }}</p>
  <div v-if="submitType === 'insert' || (submitType === 'update' && item.id )">
    <section>
      <form @submit.prevent="onSubmit">
        <div>
          <label for="id">ID</label>
          <input id="id" name="id" v-model="form.id"  type="number" placeholder="ID">
        </div>
        <input type="submit" value="Save">
      </form>
    </section>
  </div>
  `,
  props: {
    item: {
      type: Object
    },
    submitType: {
      type: String
    }
  },
  data() {
    return {
      form: {}
    }
  },
  methods: {
    fillData() {
      this.submitType === 'update' ? this.form = {...this.item} : this.form = {id: 0}
    }
  },
  watch: {
    item() {
      this.fillData()
    },
    submitType() {
      this.fillData()
    }
  },
})
app.mount('#demo')
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id="demo">
  <button @click="change">switch type</button>
  {{type}}
  <my-form :item="item" :submit-type="type"></my-form>
</div>