Push router after successfully fetching data

Viewed 2265

Is it possible to redirect a user to another page after successfully fetching/retrieving data? In this case, it's about verifying a user's email address. When the user clicks on given link in the email, he is redirected to a page where his token is sent to the backend and verified.

If the response is successful, I would like to automatically redirect the user to the "/home" page. Unfortunately it doesn't work this way.

If-statement is working, because I receive the response in the console.

<script>
export default {
  async fetch() {
    this.res = await this.$axios.$post(
      `/api/verify-mail/${this.$route.params.id}`
    )

    if (this.res.success) {
      this.$router.push('/home')
      console.log(this.res)
    }
  }
}
</script>

Edit: (Improved code)

If-condition is definitely true. I receive the response in the console. { success: true, message: 'Your account has been successfully verified' }

So, condition is working and it's writing in the console, but the router doesn't push.

If it's outside of the condition, it doesn't work too. But I discovered something interesting. If I force an error, the router can push me to the '/home' page.

async fetch() {
   try {
     const res = await this.$axios.$post(
       `/api/verify-mail/${this.$route.params.id}`
     )

     if (res.success) {
       console.log(res)
       this.$router.push('/home')
     }
   } catch (err) {
     this.$router.push('/home') // only for testing, if I force an error I will be redirected
   }
}

home.vue

<template>
  <div>
    <div v-if="getUser.isVerified === false">
      <IsVerified />
    </div>
    <div>
      <h1>Home</h1>
    </div>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import IsVerified from '../components/verify/IsVerified.vue'
export default {
  auth: false,
  components: { IsVerified },
  computed: {
    ...mapGetters(['getUser']),
  },
}
</script>

verify-mail/_id.vue

<template>
  <div>Test</div>
</template>

<script>
export default {
  data() {
    return {}
  },
  async fetch() {
    try {
      const res = await this.$axios.$post(
        `/api/verify-mail/${this.$route.params.id}`
      )

      if (res.success) {
        console.log(JSON.parse(JSON.stringify(res)))
        console.log(res)
        this.$router.push('/home')
      }
    } catch (err) {
      this.$router.push('/home') // only for testing, if I force an error
    }
  },
}
</script>

<style></style>

IsVerified.vue Component (/components/verify/IsVerified.vue)

<template>
  <div class="container">
    <div class="message">
      <p>
        Please confirm your email address
        <span class="bold">{{ getUser.email }}</span> to get full access. Token
        is only avaible for 30 minutes.
      </p>
      <button v-show="isShow" @click="sendNewToken()">Send again</button>
      <p v-show="mailSent" class="mail__sent">Email sent</p>
    </div>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
export default {
  data() {
    return {
      isShow: true,
      mailSent: false,
    }
  },

  computed: {
    ...mapGetters(['getUser']),
  },

  methods: {
    async sendNewToken() {
      try {
        const send = await this.$axios.$put('/api/send-new-verify-token', {
          data: this.getUser,
        })
        if (send.success) {
          this.isShow = false
          this.mailSent = true
        }
      } catch (err) {
        console.log(err)
      }
    },
  },
}
</script>

package.json

{
  "name": "frontend",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
    "lint": "npm run lint:js"
  },
  "dependencies": {
    "@nuxtjs/auth-next": "5.0.0-1624817847.21691f1",
    "@nuxtjs/axios": "^5.13.6",
    "@nuxtjs/recaptcha": "^1.0.4",
    "core-js": "^3.15.1",
    "nuxt": "^2.15.7",
    "sass": "^1.37.5"
  },
  "devDependencies": {
    "@babel/eslint-parser": "^7.14.7",
    "@nuxtjs/eslint-config": "^6.0.1",
    "@nuxtjs/eslint-module": "^3.0.2",
    "babel-eslint": "^10.1.0",
    "eslint": "^7.32.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-loader": "^4.0.2",
    "eslint-plugin-nuxt": "^2.0.0",
    "eslint-plugin-prettier": "^3.4.0",
    "eslint-plugin-vue": "^7.15.1",
    "prettier": "^2.3.2",
    "sass-loader": "^7.3.1"
  }
}

nuxt.config.js

const BackendURL = 'http://localhost:4000'

export default {
  head: {
    title: 'frontend',
    htmlAttrs: {
      lang: 'en',
    },
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: '' },
      { name: 'format-detection', content: 'telephone=no' },
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
  },

  css: [
    '~/assets/css/main.scss',
    '~/assets/fonts/Nunito.css',
    '~/assets/css/style.css',
  ],

  components: true,

  buildModules: ['@nuxtjs/eslint-module'],

  modules: ['@nuxtjs/axios', '@nuxtjs/auth-next', '@nuxtjs/recaptcha'],

  axios: {
    proxy: true,
    baseURL: BackendURL,
  },

  proxy: {
    '/api': BackendURL,
  },

  auth: {
    strategies: {
      local: {
        token: {
          property: 'token',
          type: 'Bearer',
          name: 'token',
        },
        user: {
          property: false,
        },
        endpoints: {
          login: { url: '/api/login', method: 'post' },
          user: { url: '/api/user', method: 'get' },
          logout: { url: '/api/logout', method: 'post' },
        },
      },
    },

    redirect: {
      login: '/', // User will be redirected to this path if login is required
      logout: '/', //User will be redirected to this path if after logout, current route is protected
      callback: '/home', //User will be redirected to this path by the identity provider after login
      home: '/home', // User will be redirected to this path after login. (rewriteRedirects: true, ... will rewrite this path)
    },
    rewriteRedirects: false,
  },

  recaptcha: {
    hideBadge: true, // Hide badge element (v3 & v2 via size=invisible)
    language: 'english',
    size: 'normal', // Size: 'compact', 'normal', 'invisible' (v2)
    siteKey: 'secret',
    version: 2,
  },

  build: {
    babel: {
      plugins: [
        ['@babel/plugin-proposal-private-property-in-object', { loose: true }],
      ],
    },
  },
}
3 Answers

Your way should work. Try to log this.$router to see if it's available / contains route information.

If you don't need res later you don't have to await the promise. Redirect to /home when the request was successfull, otherwise catch the error and to nothing.

<script>
export default {
  fetch() {
    this.$axios
      .$post(` / api / verify - mail /${this.$route.params.id}`)
      .then(() => {
        this.$router.push("/home");
      })
      .catch(error => {
        //handly error that happened during the call
      });
  }
};
</script>

This way it works without using a res object.

Try this kind of code and see if it works in your use case

<script>
export default {
  async fetch() {
    const postedObject = await this.$axios.$post('https://jsonplaceholder.typicode.com/posts', {
      title: 'foo',
      body: 'bar',
      userId: 1,
    })
    console.log('posted object >>', postedObject)
    if (postedObject.title === 'foo') {
      // try with 'baz', it will not router-push
      this.$router.push({ name: 'home' })
    }
  },
}
</script>

This kind of code should totally work. If not, there is maybe a middleware or some specific issue with your app's configuration.
A brand new Nuxt app may be required for testing purposes.

With the new version of fetch (nuxt >= 2.12), you should use: this.$nuxt.context.redirect({path:'/404'});

Related