最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Vuejs - How to use a single form to add and edit - Stack Overflow

programmeradmin1浏览0评论

I'm trying to use the same ponent to handle the Add and Edit part of my app. I'm using Firebase, so I'm checking if there is an id in the route params, if there is, it renders as the edit form, if not, renders as the add form. But this doesn't work and it has some wierd behaviour.

Here is the code for the ContactForm ponent

<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 {
  ponents: {
    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>

This is the github link and the live app

I'm trying to use the same ponent to handle the Add and Edit part of my app. I'm using Firebase, so I'm checking if there is an id in the route params, if there is, it renders as the edit form, if not, renders as the add form. But this doesn't work and it has some wierd behaviour.

Here is the code for the ContactForm ponent

<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 {
  ponents: {
    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>

This is the github link and the live app

Share Improve this question edited Dec 7, 2020 at 10:16 Serhiy 4,1413 gold badges38 silver badges66 bronze badges asked Oct 24, 2019 at 19:29 PeorayPeoray 1,9253 gold badges15 silver badges24 bronze badges 9
  • Any error message in the console? – Renaud Tarnec Commented Oct 24, 2019 at 20:02
  • no...there is nothing – Peoray Commented Oct 24, 2019 at 20:09
  • And what if you only keep the created hook? I don't think it will change anything but just trying anything that can be tried.... – Renaud Tarnec Commented Oct 24, 2019 at 20:10
  • I don't understand, can you explain further? – Peoray Commented Oct 24, 2019 at 20:13
  • You are sure there is data in your contact collection and there is no security rule that prevent reading the data? – Renaud Tarnec Commented Oct 24, 2019 at 20:13
 |  Show 4 more ments

1 Answer 1

Reset to default 5

I just cloned you repository and tested in local, Added fixes to use single form for editing and adding

Here is the code for following files, just copy paste this code in below mentioned files

src/ponents/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 {
  ponents: {
    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/ponents/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/ponents/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 "@/ponents/contact/ContactForm.vue";

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

评论列表(0)

  1. 暂无评论