Search code examples
vue-routervuejs3vue-composition-apivue-router4

Vue Router Composition API OnBeforeRouteLeave invalid navigation guard


I need to show a modal before the user leave a route and ask for confirmation. Based on that confirmation the user can leave the route. The problem is that the confirmation comes as a promise and OnBeforeRouteLeave expects a boolean return that i cannot do inside of .then(). I couldn't find anything on their API but is there a method i can use? Like next() that worked in the previous version of vue router or maybe a more suitable hook for this case?

onBeforeRouteLeave((to, from, next) => {
      if(!isEqual(store.getters['product/getProduct'], initialState)) {
        Swal.fire({
          title: 'You want to leave the page?',
          text: `There are unsaved changes that will be lost.`,
          icon: 'warning',
          showCancelButton: true,
          buttonsStyling: false,
          cancelButtonColor: '#d33',
          confirmButtonColor: '#3085d6',
          confirmButtonText: 'Yes, leave!',
          customClass: {
            confirmButton: "btn font-weight-bold btn-light-primary",
            cancelButton: "btn font-weight-bold btn-light-primary",
          },
          heightAuto: false
        }).then((result) => {
          if (result.isConfirmed) {
            store.commit('product/resetState')
            next()
          }

        })
      }
      return false
    })

Update:

On the source code it says:

Add a navigation guard that triggers whenever the component for the current location is about to be left. Similar to beforeRouteLeave but can be used in any component. The guard is removed when the component is unmounted. On beforeRouteLeave there is a next function and yet when i use it i get:

Uncaught (in promise) Error: Invalid navigation guard


Solution

  • onBeforeRouterLeave() has this signature:

    export declare function onBeforeRouteLeave(leaveGuard: NavigationGuard): void
    

    It has a void return type, which means no return is needed.

    The problem seems to be that your navigation guard is only calling next() when the if condition is met, but next() should also be called in the else case:

    onBeforeRouteLeave((to, from, next) => {
      if(!isEqual(store.getters['product/getProduct'], initialState)) {
        Swal.fire(/*...*/)
          .then(() => {
            next()
          })
      } else {
        next()
      }
    })
    

    demo