Skip to content

12. Example [nuxt-09]: Controlling Navigation

Example [nuxt-09] uses a middleware to control client navigation. Additionally, a new view is added for cases where the user requests a URL from the server that does not exist in the application.

Example [nuxt-09] is initially created by copying example [nuxt-01]:

Image

12.1. The [_.vue] page

We mentioned that the application’s routes are built from the contents of the [pages] folder. Here, we have added the [_.vue] page to this folder. This specific page is displayed whenever the application is routed to a page that does not exist. In our example here, this cannot happen for the client. But it can happen for the server if, for example, it is asked for the URL [/nuxt-09/abcd]. Since the [abcd] page does not exist, the [_.vue] page will be displayed. Here, it will look like this:

Image

The code for the [_.vue] page is as follows:


<!-- HTML definition of the view -->
<template>
  <!-- layout -->
  <Layout :left="true" :right="true">
    <!-- alert in the right column -->
    <template slot="right">
      <!-- message on yellow background -->
      <b-alert show variant="warning" align="center">
        <h4>The requested page does not exist</h4>
      </b-alert>
    </template>
    <!-- navigation menu in the left column -->
    <Navigation slot="left" />
  </Layout>
</template>

<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */

import Layout from '@/components/layout'
import Navigation from '@/components/navigation'

export default {
  name: '404',
  // components used
  components: {
    Layout,
    Navigation
  },
  // lifecycle
  beforeCreate() {
    // client and server
    console.log('[404 beforeCreate]')
  },
  created() {
    // client and server
    console.log('[404 created]')
  },
  beforeMount() {
    // client only
    console.log('[404 beforeMount]')
  },
  mounted() {
    // client only
    console.log('[404 mounted]')
  }
}
</script>

12.2. The client middleware

The client middleware code [client-routing] is as follows:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function({ route, from, redirect }) {
  // client only
  if (process.client) {
    console.log('[client-routing]')
    // desired navigation order
    const routes = ['index', 'page1', 'page2', 'index']
    // current route
    const current = route.name
    // previous route
    const previous = from.name
    // we want circular navigation
    // routes[i] to routes[i+1]
    for (let i = 0; i < routes.length - 1; i++) {
      if (previous === routes[i] && current !== routes[i + 1]) {
        // stay on the same page
        redirect({ name: routes[i] })
        return
      }
    }
  }
}
  • Line 3: We know that the routing function takes only one parameter, the [context] object of the entity executing it, whether it be the server or the client. The notation [function({ route, from, redirect })]
    • is equivalent to [function({ route:route, from:from, redirect:redirect })];
    • which means that { route:route, from:from, redirect:redirect } <-- context;
    • which creates three parameters [route, from, redirect] such as:
      • route=context.route;
      • redirect=context.redirect;
      • from=context.from;

The [nuxt] documentation makes extensive use of this notation. It is important to be familiar with it;

  • line 8: an array of page names in the desired navigation order
  • line 10: the name of the destination page for the current route;
  • line 12: the name of the previous page in the current routing;
  • Line 14: As an exercise, we will only allow circular navigation [index --> page1 --> page2 --> index];
  • lines 15–21: we iterate through the array to determine the desired navigation order;
  • line 16: if we find that routes[i] was the last page navigated to, then the next one must be routes[i+1];
  • lines 18–19: if this is not the case, we redirect the application to routes[i], i.e., we do not change pages: we reject the navigation;

12.3. Execution

We run the example with the following [nuxt.config.js] file:


export default {
  mode: 'universal',
  /*
   ** Page headers
   */
  head: {
    title: process.env.npm_package_name || "Introduction to Nuxt.js through examples",
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: process.env.npm_package_description || '' }
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
  },
  /*
   ** Customize the progress bar color
   */
  loading: { color: '#fff' },
  /*
   ** Global CSS
   */
  css: [],
  /*
   ** Plugins to load before mounting the App
   */
  plugins: [],
  /*
   ** Nuxt.js dev-modules
   */
  buildModules: [
    // Doc: https://github.com/nuxt-community/eslint-module
    '@nuxtjs/eslint-module'
  ],
  /*
   ** Nuxt.js modules
   */
  modules: [
    // Doc: https://bootstrap-vue.js.org
    'bootstrap-vue/nuxt',
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios'
  ],
  /*
   ** Axios module configuration
   ** See https://axios.nuxtjs.org/options
   */
  axios: {},
  /*
   ** Build configuration
   */
  build: {
    /*
     ** You can extend the Webpack configuration here
     */
    extend(config, ctx) {}
  },
  // source code directory
  srcDir: 'nuxt-09',
  router: {
    base: '/nuxt-09/',
    middleware: ['client-routing']
  },
  // server
  server: {
    port: 81, // default: 3000
    host: 'localhost' // default: localhost
  }
}

Check the following:

  • when you are on the [Home] page, you can only navigate to the [Page 1] page;
  • when you are on the [Page 1] page, you can only navigate to the [Page 2] page;
  • when you are on the [Page 2] page, you can only navigate to the [Home] page;
  • When you request an invalid URL such as [http://localhost:81/nuxt-09b/abcd], you get a view indicating that the requested page does not exist;