Vue Final Project - Part 7 - Some odds and ends

Why We Aren't Deleting Users

We could easily add functionality to delete users, which might be OK when using the JSON server as our back-end. But when we integrate our Vue app with the API that you are working on in Adv Topics, our data will be stored in a relational database. Deleting rows from a database could be tricky because of foreign key relationships. For example, if your project keeps track of recipies that users enter into the system, then if you delete a user then you most likely have to delete all of their recipies first. Some people believe that you should never delete rows from certain tables because then you may never be able to recover the data. Instead you can do what's often called a virtual delete. For examle, instead of deleting a user, instead you might set them to inactive. You could then code the app so that an inactive user cannot log in.

Decomposing the Nav Bar

We have been studying component-based design in this class, which calls for breaking pages down into smaller pieces (components). In this step decompose the nav bar and separate the code for it into a component named NavBar.

Create a file in the components folder named NavBar.vue. To quickly add the boiler plate code for the component, type in 'vue' and press tab. This should add a TEMPLATE, SCRIPT, and STYLE element to the file (as long as you have installed the Vetur plugin in VSCode).

Then open App.vue and cut the NAV element out of the template, and paste it into the template of NavBar.vue.

You'll also need to cut the inject and methods properties from App.vue and paste them into the options object in NavBar.vue.

Import the NavBar component in App.vue

import NavBar from '@/components/NavBar.vue';

When you import a component you must also 'register' it by adding a components property to the options object (in App.vue). You can put this line above the inject property:

components: { NavBar },

Then add a <nav-bar> element to the template.

Reminder - You will have to Bootstrap the Nav Bar for your final project

The About Page

If you don't plan on using the About component in your final project you should remove it by doing the following:

  1. Remove the import statement in the router file.
  2. Remove the router-link to it in App.vue
  3. Remove About.vue from the views folder

Setting Page Titles

To add a title for each page (which will appear in the browser tab) add a meta property to each object in the routes array (in router/index.js). The value of the meta property should be an object that has a 'title' property. You can set the value of the title property appropriately for each route. For example, here is what the Home route should look like:

const routes = [
  { path: '/', name: 'Home', component: Home, meta: {title: "Home Page"} },
  //the rest of the routes come after this one

You don't need to add a meta property to the catchAll route, since it just redirects to the 404/NotFound route.

Now we'll hook into the router and set the page title after each page is displayed. Add this code just above the export statement in the router file (it must be placed after the code that calls createRouter():

router.afterEach((to, from) => {
  document.title = to.meta.title || "NO PAGE TITLE SET!";
});

The arrow function that is passed into the afterEach() method of the router object will be triggered/invoked after the router have navigated to a new route. The to param will be the router object that we are navigating to. You could also access the route that have just navigated from by accessing the from parameter. In JavaScript, you can set the title of a page by altering the title property of the document object.

OPTIONAL: Restructuring the Navigation for Users

Websites organize pages in a hierarchical fashion. Vue allows you to organize app like this, but it's a little tricky.

Create a file named Users.vue in the views folder and add this code to it:

<template>
    <div>
      <h3>
        <span v-if="$route.name == 'UserList'">Users</span>
        <span v-else-if="$route.name == 'UserDetails'">User Details</span>
        <span v-else-if="$route.name == 'AddUser'">Add User</span>
      </h3>
      <router-link v-if="$route.name == 'UserList'" :to="{ name: 'AddUser' }">Add New User</router-link>
      <router-link v-else :to="{ name: 'UserList' }">Back to Users</router-link>
      <router-view></router-view>
    </div>
</template>

We can talk about this code in class. It's a little tricky and it makes heavy use of the v-if directives. But note that the User.vue component contains a router-view element. This router-view element will become a container that can display the UserList or the UserDetails. And note that you can use $route.name to determine which component is being displayed inside the router-view element

Import the Users component in the router file:

import Users from '../views/Users.vue'

Now, in the router file, remove all the route objects where the path starts with /users (there should be 3 of them). And replace them with this object:

{
  path: '/users', component: Users,
  children: [
    { path: '/users', name: "UserList", component: UserList, meta: { title: "Users" } },
    { path: '/users/:userId', name: 'UserDetails', component: UserDetails, props: true, meta: { title: "Edit User" } },
    { path: '/users/add', name: 'AddUser', component: UserDetails, meta: { title: "Add User" } },
  ]
},

The Users component is now a container that will display either the UserList component or the UserDetails component. It will default to displaying the UserList compoent because the path for the UserList component is /users, which matches the path of the parent.

It might be hard to tell from this example, but this allows you to build your apps in sections.

Now you can remove the BUTTON element that is currently in the UserList component. It has been replaced the the router-link that we put in the Users component.

The UserList and UserDetails components are technically no longer 'pages', so we should move them into the components folder. This would also require you to update the import statements for them in the router file.