From 99fd583f0e0221e10373c5b8f0f4700fe06222b7 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Wed, 11 Nov 2020 10:06:54 -0500 Subject: [PATCH] pass props --- packages/vue-router/src/types.ts | 1 + packages/vue-router/src/viewStacks.ts | 3 +- .../vue/src/components/IonRouterOutlet.ts | 35 ++++- .../vue/test-app/tests/unit/routing.spec.ts | 123 ++++++++++++++++++ 4 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 packages/vue/test-app/tests/unit/routing.spec.ts diff --git a/packages/vue-router/src/types.ts b/packages/vue-router/src/types.ts index 79700f08d9f..0be36407361 100644 --- a/packages/vue-router/src/types.ts +++ b/packages/vue-router/src/types.ts @@ -42,6 +42,7 @@ export interface ViewItem { exact: boolean; registerCallback?: () => void; vueComponentRef: Ref; + params?: { [k: string]: any }; } export interface ViewStacks { diff --git a/packages/vue-router/src/viewStacks.ts b/packages/vue-router/src/viewStacks.ts index 6c867329799..c7b8e54364f 100644 --- a/packages/vue-router/src/viewStacks.ts +++ b/packages/vue-router/src/viewStacks.ts @@ -88,7 +88,8 @@ export const createViewStacks = () => { vueComponentRef: shallowRef(), ionRoute: false, mount: false, - exact: routeInfo.pathname === matchedRoute.path + exact: routeInfo.pathname === matchedRoute.path, + params: routeInfo.params }; } diff --git a/packages/vue/src/components/IonRouterOutlet.ts b/packages/vue/src/components/IonRouterOutlet.ts index f337152bc24..a996cf378cc 100644 --- a/packages/vue/src/components/IonRouterOutlet.ts +++ b/packages/vue/src/components/IonRouterOutlet.ts @@ -355,15 +355,36 @@ export const IonRouterOutlet = defineComponent({ { ref: 'ionRouterOutlet' }, // TODO types components && components.map((c: any) => { + let props = { + ref: c.vueComponentRef, + key: c.pathname, + isInOutlet: true, + registerIonPage: (ionPageEl: HTMLElement) => registerIonPage(c, ionPageEl) + } + + /** + * IonRouterOutlet does not support named outlets. + */ + if (c.matchedRoute?.props?.default) { + const matchedRoute = c.matchedRoute; + const routePropsOption = matchedRoute.props.default; + const routeProps = routePropsOption + ? routePropsOption === true + ? c.params + : typeof routePropsOption === 'function' + ? routePropsOption(matchedRoute) + : routePropsOption + : null + + props = { + ...props, + ...routeProps + } + } return h( c.vueComponent, - { - ref: c.vueComponentRef, - key: c.pathname, - isInOutlet: true, - registerIonPage: (ionPageEl: HTMLElement) => registerIonPage(c, ionPageEl) - } - ) + props + ); }) ) } diff --git a/packages/vue/test-app/tests/unit/routing.spec.ts b/packages/vue/test-app/tests/unit/routing.spec.ts new file mode 100644 index 00000000000..ef3f80ffc02 --- /dev/null +++ b/packages/vue/test-app/tests/unit/routing.spec.ts @@ -0,0 +1,123 @@ +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from '@ionic/vue-router'; +import { IonicVue, IonApp, IonRouterOutlet, IonPage, IonTabs, IonTabBar } from '@ionic/vue'; + +const App = { + components: { IonApp, IonRouterOutlet }, + template: '', +} + +const BasePage = { + template: '', + components: { IonPage }, +} + +describe('Routing', () => { + it('should pass no props', async () => { + const Page1 = { + ...BasePage, + props: { + title: { type: String, default: 'Default Title' } + } + }; + + const router = createRouter({ + history: createWebHistory(process.env.BASE_URL), + routes: [ + { path: '/', component: Page1 } + ] + }); + + router.push('/'); + await router.isReady(); + const wrapper = mount(App, { + global: { + plugins: [router, IonicVue] + } + }); + + const cmp = wrapper.findComponent(Page1); + expect(cmp.props()).toEqual({ title: 'Default Title' }); + }); + + it('should pass route props as an object', async () => { + const Page1 = { + ...BasePage, + props: { + title: { type: String, default: 'Default Title' } + } + }; + + const router = createRouter({ + history: createWebHistory(process.env.BASE_URL), + routes: [ + { path: '/', component: Page1, props: { title: 'Page 1 Title' } } + ] + }); + + router.push('/'); + await router.isReady(); + const wrapper = mount(App, { + global: { + plugins: [router, IonicVue] + } + }); + + const cmp = wrapper.findComponent(Page1); + expect(cmp.props()).toEqual({ title: 'Page 1 Title' }); + }); + + it('should pass route props as a function', async () => { + const Page1 = { + ...BasePage, + props: { + title: { type: String, default: 'Default Title' } + } + }; + + const router = createRouter({ + history: createWebHistory(process.env.BASE_URL), + routes: [ + { path: '/myPath', component: Page1, props: function(route) { return { title: `${route.path} Title` } } } + ] + }); + + router.push('/myPath'); + await router.isReady(); + const wrapper = mount(App, { + global: { + plugins: [router, IonicVue] + } + }); + + const cmp = wrapper.findComponent(Page1); + expect(cmp.props()).toEqual({ title: '/myPath Title' }); + }); + + it('should pass route params as props', async () => { + const Page1 = { + ...BasePage, + props: { + title: { type: String, default: 'Default Title' } + } + }; + + const router = createRouter({ + history: createWebHistory(process.env.BASE_URL), + routes: [ + { path: '/:title', component: Page1, props: true } + ] + }); + + router.push('/myPath'); + await router.isReady(); + const wrapper = mount(App, { + global: { + plugins: [router, IonicVue] + } + }); + + const cmp = wrapper.findComponent(Page1); + expect(cmp.props()).toEqual({ title: 'myPath' }); + }); +});