2
votes

I'm trying to create an application in which we can create a Book instance that has a name, description, publishing date, etc. For the frontend, I'm using Vuejs and the Backend is Django.

For creating a new Book instance, I've created a view called BookEditor.vue. I'm trying to use the same view to edit the Book instance.

To edit the book, a router link is placed in another component called BookActions.vue.

<template>
  <div>
    <router-link
      :to="{ name: 'book-editor', params: { slug: slug } }"
      >Edit
    </router-link>
  </div>
</template>

<script>
import { apiService } from "@/common/api.service";

export default {
  name: "BookActions",
  props: {
    slug: {
      type: String,
      required: true,
    },
  }
};
</script>

When the router link is clicked the user is navigated to BookEditor.vue. Following is the router code.

const routes = [
  {
    path: "/book-editor/:slug?",
    name: "book-editor",
    component: BookEditor
  }
];

Following is the BookEditor.vue code.

export default {
  name: "BookEditor",
  props: {
    slug: {
      type: String,
      required: false,
    },
  },
  data() {
    return {
      tag_id_list: [],
      published_on: null,
      book_name: null,
      book_description: null,
      error: null,
      isUpdateEditor: false,
    };
  },
  methods: {
    onSubmit() {
       if {.....}
       else {
        let endpoint = "/api/books/";
        let method = "POST";
        if (this.slug !== undefined) {
          endpoint += `${this.slug}/`;
          method = "PUT";
        }
        apiService(endpoint, method, {
          name: this.book_name,
          published_on: this.published_on,
          description: this.book_description,
          tag_id_list: this.tag_id_list,
        }).then((book_data) => {
          this.$router.push({
            name: "book",
            params: { slug: book_data.slug },
          });
        });
      }
    },
  },
  async beforeRouteEnter(to, from, next) {
    if (to.params.slug !== undefined) {
      let endpoint = `/api/books/${to.params.slug}/`;
      let data = await apiService(endpoint);
      return next((vm) => {
        (vm.book_name = data.name),
          (vm.started_on = data.started_on),
          (vm.published_on= data.published_on),
          (vm.isUpdateEditor = true);
      });
    } else {
      return next();
    }
  },
  created() {
    document.title = "Book Editor";
  },
};
</script>

When the user is navigated to the Book Editor, the slug prop is undefined, and a new book is always created if we try to update any book.

I've explored various questions but to no avail.

1

1 Answers

3
votes

Your beforeRouteEnter guard should be working so I assume your question is about onSubmit accessing the this.slug prop. You have to set props: true in your route definition for route params to be assigned to props:

const routes = [
  {
    path: "/book-editor/:slug?",
    name: "book-editor",
    component: BookEditor,
    props: true       // <-- Add this
  }
];

From the Vue Router docs:

When props is set to true, the route.params will be set as the component props.