Answer a question

I'm trying to use the same component 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 component

<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>

This is the github link and the live app

Answers

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/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>
Logo

Vue社区为您提供最前沿的新闻资讯和知识内容

更多推荐