Vuejs - 如何使用单个表单添加和编辑

Posted

技术标签:

【中文标题】Vuejs - 如何使用单个表单添加和编辑【英文标题】:Vuejs - How to use a single form to add and edit 【发布时间】:2020-02-21 04:28:15 【问题描述】:

我正在尝试使用相同的组件来处理我的应用程序的添加和编辑部分。我正在使用 Firebase,所以我正在检查路由参数中是否有 id,如果有,它将呈现为编辑表单,如果没有,则呈现为添加表单。但这不起作用,而且有一些奇怪的行为。

这是ContactForm 组件的代码

<template>
  <div>
    <div class="card mb-3">
      <div class="card-header"> editing ? 'Edit' : 'Add'  Contact</div>
      <div class="card-body">
        <form @submit.prevent="addContact">
          <TextInputGroup
            label="Name"
            name="name"
            placeholder="Enter your name..."
            v-model="contact.name"
            for="name"
          />
          <TextInputGroup
            type="email"
            label="Email"
            name="email"
            placeholder="Enter your email..."
            v-model="contact.email"
          />
          <TextInputGroup
            type="phone"
            label="Phone"
            name="phone"
            placeholder="Enter your phone number..."
            v-model="contact.phone"
          />

          <input type="submit" value="Add Contact" class="btn btn-block btn-light" />
        </form>
      </div>
    </div>
  </div>
</template>

<script>
import TextInputGroup from "../layout/TextInputGroup";
import  db  from "../../firebase";

export default 
  components: 
    TextInputGroup
  ,
  data() 
    return 
      contact: "",
      editing: false,
      email: "",
      name: "",
      phone: ""
    ;
  ,
  methods: 
    addContact() 
      const newContact = 
        name: this.name,
        email: this.email,
        phone: this.phone,
        createdAt: new Date()
      ;
      db.collection("contacts")
        .add(newContact)
        .then(docRef => 
          console.log("Document written with ID: ", docRef.id);
        )
        .catch(error => 
          console.error("Error adding document: ", error);
        );
      this.$router.push("/");
    ,
    getContactById() 
      db.collection("contacts")
        .doc(this.$route.params.id)
        .get()
        .then(snapshot => 
          if (!snapshot.exists) return;
          this.contact = snapshot.data();
        );
    ,
    updateContact() 
      const newContact = 
        name: this.contact.name,
        email: this.contact.email,
        phone: this.contact.phone
      ;
      db.collection("contacts")
        .doc(this.$route.params.id)
        .update(newContact)
        .then(() => 
          console.log("Updated document with ID: ");
        )
        .catch(function(error) 
          console.error("Error updating document: ", error);
        );
      this.$router.push("/");
    
  ,
  mounted() 
    if ("id" in this.$route.params) 
      this.getContactById();
      this.editing = true;
      console.log("id");
     else 
      console.log("ups");
      // this
    
  
;
</script>

这是github link 和live app

【问题讨论】:

控制台中有错误信息吗? 不...什么都没有 如果你只保留创建的钩子呢?我认为它不会改变任何东西,只是尝试任何可以尝试的东西...... 我不明白,你能解释一下吗? 您确定您的联系人集合中有数据并且没有阻止读取数据的安全规则? 【参考方案1】:

我刚刚克隆了您的存储库并在本地进行了测试,添加了修复以使用单一表单进行编辑和添加

这是以下文件的代码,只需将此代码复制粘贴到以下文件中

src/components/contact/ContactForm.vue

<template>
  <div>
    <div class="card mb-3">
      <div class="card-header"> editing ? 'Edit' : 'Add'  Contact</div>
      <div class="card-body">
        <form @submit.prevent="addContact">
          <TextInputGroup
            label="Name"
            name="name"
            placeholder="Enter your name..."
            v-model="contact.name"
            for="name"
          />
          <TextInputGroup
            type="email"
            label="Email"
            name="email"
            placeholder="Enter your email..."
            v-model="contact.email"
          />
          <TextInputGroup
            type="phone"
            label="Phone"
            name="phone"
            placeholder="Enter your phone number..."
            v-model="contact.phone"
          />

          <input type="submit" value="Add Contact" class="btn btn-block btn-light" />
        </form>
      </div>
    </div>
  </div>
</template>

<script>
import TextInputGroup from "../layout/TextInputGroup";
import  db  from "../../firebase";

var temp = Object.freeze(
      name: '',
      email: '',
      phone: '',
    );

export default 
  components: 
    TextInputGroup
  ,
  props: 
    type: 
      type: String,
      default: '',
    ,
  ,
  data() 
    

    return 
      contact: Object.assign(, temp),
      editing: false,
    ;
  ,
  methods: 
    addContact() 
      this.contact.createdAt = new Date();
      db.collection("contacts")
        .add(this.contact)
        .then(docRef => 
          console.log("Document written with ID: ", docRef.id);
        )
        .catch(error => 
          console.error("Error adding document: ", error);
        );
      this.$router.push("/");
    ,
    getContactById() 
      db.collection("contacts")
        .doc(this.$route.params.id)
        .get()
        .then(snapshot => 
          if (!snapshot.exists) return;
          this.contact = snapshot.data();
        );
    ,
    updateContact() 
      db.collection("contacts")
        .doc(this.$route.params.id)
        .update(this.contact)
        .then(() => 
          console.log("Updated document with ID: ");
        )
        .catch(function(error) 
          console.error("Error updating document: ", error);
        );
      this.$router.push("/");
    
  ,
  created() 
    if ("id" in this.$route.params) 
      this.getContactById();
      this.editing = true;
      console.log("id");
     else 
      console.log("ups");
      // this
    
  ,
  watch: 
    type(val) 
      if (val == 'add') 
        this.contact = Object.assign(, temp);
      
    
  
;
</script>

src/components/contact/ContactItem.vue

<template>
  <div>
    <div class="card card-body mb-3">
      <h4>
         contact.name 
        <i
          class="fas fa-sort-down pointer"
          @click="showContactInfo = !showContactInfo"
        ></i>
        <i class="fas fa-times delete right delete" @click="deleteContact(contact.id)"></i>
        <router-link :to="path: `contact/edit/$contact.id`, params:  id: contact.id , query:  type: 'edit' ">
          <i class="fas fa-pencil-alt edit right"></i>
        </router-link>
      </h4>
      <ul class="list-group" v-if="showContactInfo">
        <li class="list-group-item">Email:  contact.email </li>
        <li class="list-group-item">Phone:  contact.phone </li>
      </ul>
    </div>
  </div>
</template>

<script>
import  db  from "../../firebase";

export default 
  props: 
    contact: 
      type: Object,
      required: true
    
  ,
  data() 
    return 
      showContactInfo: false
    ;
  ,
  methods: 
    deleteContact(id) 
      db.collection("contacts")
        .doc(id)
        .delete()
        .then(function() 
          console.log("Document successfully deleted!");
        )
        .catch(function(error) 
          console.error("Error removing document: ", error);
        );
    
  
;
</script>

<style scoped>
.pointer 
  cursor: pointer;

.right 
  cursor: pointer;
  float: right;


.edit 
  color: black;
  margin-right: 1rem;


.delete 
  color: red;

</style>

src/components/layout/Navbar.vue

<template>
  <div>
    <nav class="navbar navbar-expand-sm navbar-dark bg-danger mb-3 py-0">
      <div class="container">
        <a href="/" class="navbar-brand">Contact Manager</a>
        <div>
          <ul class="navbar-nav mr-auto">
            <li class="nav-item">
              <router-link to="/" class="nav-link">
                <i class="fas fa-home" />
                Home
              </router-link>
            </li>
            <li class="nav-item">
              <router-link :to=" path: '/contact/add', query:  type: 'add'  " class="nav-link">
                <i class="fas fa-plus" />
                Add
              </router-link>
            </li>
            <li class="nav-item">
              <router-link to="/about" class="nav-link">
                <i class="fas fa-question" />
                About
              </router-link>
            </li>
          </ul>
        </div>
      </div>
    </nav>
  </div>
</template>

src/views/ContactForm.vue

<template>
  <ContactForm :type="formType" />
</template>

<script>
// @ is an alias to /src
import ContactForm from "@/components/contact/ContactForm.vue";

export default 
  name: "home",
  data() 
    return 
      formType: '',
    ;
  ,
  components: 
    ContactForm
  ,
  watch:  
   '$route.query.type': 
      handler: function(type) 
        this.formType = type;
      ,
      deep: true,
      immediate: true
    
  
;
</script>

【讨论】:

感谢您抽出宝贵时间提供帮助。你能解释一下你的代码吗?我不想只是复制和粘贴:) 是的,当你想添加一个新联系人时,this.contact 在创建时会有一个空表单,但是当你有一个 id 时,这意味着编辑,你会得到你的 this.contact 预填充基于 id 的联系人。以前,您在此组件中全局拥有姓名、电子邮件、电话,而不是仅依赖 this.contact。现在我已经重构为 add 和 edit 共享此表单。您还有其他说明吗? ,如果不接受并赞成这个答案 另外,问题似乎仍然存在。尝试单击编辑图标使表单显示为编辑模式,然后尝试单击导航栏中的 添加 链接,您会注意到尽管 URL 已更改,但仍处于编辑模式 我理解你的解释,但这并不能解决问题。虽然它之前工作过,但当我点击主页上的 编辑图标 时,我的表单会被预先填写。主要问题是获得正确的表单以正确呈现如上所述 这就是你写的逻辑,添加 else 块,如果没有 id 存在,它应该重置 this.contact 对象

以上是关于Vuejs - 如何使用单个表单添加和编辑的主要内容,如果未能解决你的问题,请参考以下文章

如何在 VueJS 文件中添加 Laravel CSRF 令牌? [复制]

在 vuejs 中提交表单,我应该使用表单标签吗?

如何将 vue 单个组件模板部分拆分为更小的子模板

如何使用VueJS和Vuex重置表单元素

如何在 vuejs 组件中使用 laravel csrf 令牌

如何使用相同的 django 表单编辑/添加对象?