]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
feat: add onBeforeRouteUpdate
authorEduardo San Martin Morote <posva13@gmail.com>
Tue, 28 Apr 2020 09:07:45 +0000 (11:07 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Tue, 28 Apr 2020 09:07:45 +0000 (11:07 +0200)
__tests__/guards/onBeforeRouteUpdate.spec.ts [new file with mode: 0644]
__tests__/matcher/records.spec.ts
src/index.ts
src/matcher/index.ts
src/matcher/types.ts
src/navigationGuards.ts
src/router.ts

diff --git a/__tests__/guards/onBeforeRouteUpdate.spec.ts b/__tests__/guards/onBeforeRouteUpdate.spec.ts
new file mode 100644 (file)
index 0000000..4762d36
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * @jest-environment jsdom
+ */
+import {
+  createRouter,
+  createMemoryHistory,
+  onBeforeRouteUpdate,
+} from '../../src'
+import { createApp, defineComponent } from 'vue'
+
+const component = {
+  template: '<div>Generic</div>',
+}
+
+describe('onBeforeRouteUpdate', () => {
+  it('invokes with the component context', async () => {
+    expect.assertions(2)
+    const spy = jest
+      .fn()
+      .mockImplementationOnce(function (this: any, to, from, next) {
+        expect(typeof this.counter).toBe('number')
+        next()
+      })
+    const WithLeave = defineComponent({
+      template: `text`,
+      // we use data to check if the context is the right one because saving `this` in a variable logs a few warnings
+      data: () => ({ counter: 0 }),
+      setup() {
+        onBeforeRouteUpdate(spy)
+      },
+    })
+
+    const router = createRouter({
+      history: createMemoryHistory(),
+      routes: [
+        { path: '/', component },
+        { path: '/foo', component: WithLeave as any },
+      ],
+    })
+    const app = createApp({
+      template: `
+      <router-view />
+      `,
+    })
+    app.use(router)
+    const rootEl = document.createElement('div')
+    document.body.appendChild(rootEl)
+    app.mount(rootEl)
+
+    await router.isReady()
+    await router.push('/foo')
+    await router.push('/foo?q')
+    expect(spy).toHaveBeenCalledTimes(1)
+  })
+})
index afb168c311d2fe1511a9e0408b02190b157857ee..aa25b11545e1e8e17503d9ac38dc9e6c326291da 100644 (file)
@@ -12,6 +12,7 @@ describe('normalizeRouteRecord', () => {
       aliasOf: undefined,
       components: { default: {} },
       leaveGuards: [],
+      updateGuards: [],
       instances: {},
       meta: {},
       name: undefined,
@@ -35,6 +36,7 @@ describe('normalizeRouteRecord', () => {
       children: [{ path: '/child' }],
       components: { default: {} },
       leaveGuards: [],
+      updateGuards: [],
       instances: {},
       meta: { foo: true },
       name: 'name',
@@ -76,6 +78,7 @@ describe('normalizeRouteRecord', () => {
       children: [{ path: '/child' }],
       components: { one: {} },
       leaveGuards: [],
+      updateGuards: [],
       instances: {},
       meta: { foo: true },
       name: 'name',
index 8a3e46d1a30bd42f679da5a91400213776d8452d..7495b1eb528ef9176e49b9de542382d2642c1513 100644 (file)
@@ -37,7 +37,7 @@ export {
 
 export { NavigationFailureType, NavigationFailure } from './errors'
 
-export { onBeforeRouteLeave } from './navigationGuards'
+export { onBeforeRouteLeave, onBeforeRouteUpdate } from './navigationGuards'
 export { RouterLink, useLink } from './RouterLink'
 export { RouterView } from './RouterView'
 
index 0c01858471e12518acf55211c95824bffeca5e05..9cd960dfdfc87a109bac79af628a3d5a5928f59a 100644 (file)
@@ -304,6 +304,7 @@ export function normalizeRouteRecord(
       children: record.children || [],
       instances: {},
       leaveGuards: [],
+      updateGuards: [],
       components:
         'components' in record
           ? record.components
index ccf9d059265010901912a14ebed28404806b002a..8ce537a1c7a56ef622ad50bf338790fda80584bb 100644 (file)
@@ -16,6 +16,7 @@ export interface RouteRecordNormalized {
   props: Exclude<_RouteRecordBase['props'], void>
   beforeEnter: RouteRecordMultipleViews['beforeEnter']
   leaveGuards: NavigationGuard[]
+  updateGuards: NavigationGuard[]
   instances: Record<string, ComponentPublicInstance | undefined | null>
   // can only be of of the same type as this record
   aliasOf: RouteRecordNormalized | undefined
index 9801288691bd9bf3ff9b338672af2fbdcc2210f2..a5c78ec54dc66aaeca3ae2bce79d6d9345c4bd43 100644 (file)
@@ -26,15 +26,18 @@ export function onBeforeRouteLeave(leaveGuard: NavigationGuard) {
   const instance = getCurrentInstance()
   if (!instance) {
     __DEV__ &&
-      warn('onRouteLeave must be called at the top of a setup function')
+      warn('onBeforeRouteLeave must be called at the top of a setup function')
     return
   }
 
-  const activeRecord = inject(matchedRouteKey, {} as any).value
+  const activeRecord: RouteRecordNormalized | undefined = inject(
+    matchedRouteKey,
+    {} as any
+  ).value
 
   if (!activeRecord) {
     __DEV__ &&
-      warn('onRouteLeave must be called at the top of a setup function')
+      warn('onBeforeRouteLeave must be called at the top of a setup function')
     return
   }
 
@@ -44,6 +47,31 @@ export function onBeforeRouteLeave(leaveGuard: NavigationGuard) {
   )
 }
 
+export function onBeforeRouteUpdate(updateGuard: NavigationGuard) {
+  const instance = getCurrentInstance()
+  if (!instance) {
+    __DEV__ &&
+      warn('onBeforeRouteUpdate must be called at the top of a setup function')
+    return
+  }
+
+  const activeRecord: RouteRecordNormalized | undefined = inject(
+    matchedRouteKey,
+    {} as any
+  ).value
+
+  if (!activeRecord) {
+    __DEV__ &&
+      warn('onBeforeRouteUpdate must be called at the top of a setup function')
+    return
+  }
+
+  activeRecord.updateGuards.push(
+    // @ts-ignore do we even want to allow that? Passing the context in a composition api hook doesn't make sense
+    updateGuard.bind(instance.proxy)
+  )
+}
+
 export function guardToPromiseFn(
   guard: NavigationGuard,
   to: RouteLocationNormalized,
index 74da53a885cb616b172009f33f9b82a1a6b44f18..26dd3cc7f7702a4d68f286d1c18da881ce55971f 100644 (file)
@@ -395,7 +395,7 @@ export function createRouter({
 
     const [
       leavingRecords,
-      // updatingRecords,
+      updatingRecords,
       // enteringRecords,
     ] = extractChangingRecords(to, from)
 
@@ -425,6 +425,12 @@ export function createRouter({
           from
         )
 
+        for (const record of updatingRecords) {
+          for (const guard of record.updateGuards) {
+            guards.push(guardToPromiseFn(guard, to, from))
+          }
+        }
+
         // run the queue of per route beforeEnter guards
         return runGuardQueue(guards)
       })