Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Control modals using vue router

Tags:

I am working in the project developed with Vue 2 with VueRouter and I am trying to work with my modals controlled by my VueRouter!

I've done the following code

Main vue component: My normal components will be loaded on the default router-view and all my modals will be loaded on the modal router-view

<div id="app">    <router-view v-if="!isLoading"></router-view>    <router-view v-if="!isLoading" name="modal"></router-view>  </div>

RoutedModals Mixing As you can see on my beforeRouteEnter method I am checking if there is a previous "from" route (which means the user got the page navigating inside the app)... If it's I set that one as default component... if not (which means the user got directly from the URL) I set my dashboard as default and it will be opened behind my modal.

import Dashboard from 'modules/dashboard/components/Main.vue'  import { isNil } from 'lodash'    export default {    data() {        return {          canAccessDirect: true,          goBackTo: '/'        }      },      beforeRouteEnter(to, from, next) {        to.matched[0].components.default = isNil(from.matched[0]) ? Dashboard : from.matched[0].components.default          next(vm => {          if (!vm.canAccessDirect)            vm.$router.push({              name: 'dashboard.index'            })            vm.fetchRecords()          vm.goBackTo = from.path          window.jQuery(vm.$el).modal('show')          window.jQuery(vm.$el).on('hide.bs.modal', () => {            vm.$router.push(vm.goBackTo)          })        })      },      beforeRouteLeave(to, from, next) {        setTimeout(() => {          next()        }, 200)      },      methods: {        fetchRecords() {          // Do list request        }      }  }

An example of my router object: The first route will open a modal on the router-view modal and the second will open only on the default router-view

{    name: 'leads.quick-add',    path: '/leads/quick-add',    components: { modal: QuickAdd },  },   {    name: 'leads.index',    path: '/leads',    component: Main,  },

It works great! The problem comes when I access my modal URL (does not matter if it's directly or navigating) and the default component has a child component! The child component get away on that case!

There is attached some screenshots to help you out understand what happens...

Image 1 enter image description here

Image 2 enter image description here

At Image 1 we can 2 components where the number 1 is my default component on my VueRouter and the number 2 is his child!

Ar the Image 2, after clicking on the + Quotation button the modal is loaded and the component number 2 getaway!

Any ideas on how to do it keeping the others components?

Just to be clear I want to do it by routing and no calling my modal manually!

########################## Edit I am trying to do something like that instead of check on beforeRouterEnter method:

{    name: 'leads.show.quotations.create',    path: '/leads/:id/quotations/create',    components: {      default: Show,      'default.tab': Quotations,      modal: Add    },    meta: {      requiresAuth: true    }  },

Where there is a sub-router-view but it does not work!

Thinking about possibilities I've added this issue on the github repo: https://github.com/vuejs/vue-router/issues/1030

like image 933
Gustavo Bissolli Avatar asked Dec 20 '16 19:12

Gustavo Bissolli


People also ask

How do you pass props through the Vue route?

The URL /search? q=vue would pass {query: 'vue'} as props to the SearchUser component. Try to keep the props function stateless, as it's only evaluated on route changes. Use a wrapper component if you need state to define the props, that way vue can react to state changes.

Can you pass Props to router view Vue?

Vue Router 4 provides multiple ways of doing this: from setting the props property on the route record to true and automatically passing all params as props, setting the props property to a static object to provide static props, or setting it to a function that returns the desired props.


1 Answers

I did this in a project at work. It is quite simple actually, the hard part lies in mixing the jquery that you have there, and maybe the css to position a modal, since it's entry point is the router-view inside your component I recommend using the package portal-vue to move the modal content to the end of the body.

Here is a working exemple: https://codesandbox.io/s/vue-router-modal-j10t2

First create a Modal Component that receives it's child by props:

<template>   <portal to="modal">     <div class="modal-wrapper">       <div class="overlay" @click="$router.back()"></div>       <div class="modal">         <!-- you can use v-bind to pass down all props -->         <component :is="component" v-bind="$attrs"/>       </div>     </div>   </portal> </template>  <script> export default {   name: "Modal",   props: ["component"], }; </script>  <style scoped> .modal-wrapper {   position: absolute;   top: 0;   left: 0;   width: 100vw;   height: 100vh; } .modal {   position: absolute;   z-index: 1;   margin: auto;   left: 50%;   top: 50%;   transform: translate(-50%, -50%);   background-color: white;   padding: 5em;   border: 1px solid #ccc;   border-radius: 1em;   box-shadow: 0 0 1em #00000033; }  .overlay {   z-index: 1;   position: absolute;   width: 100vw;   height: 100vh;   background-color: #00000055; } </style>  

Then you can use the props in routes to assign the content for a given route:

import Home from "./Home.vue"; import Modal from "./Modal.vue"; import Content from "./Content.vue";  const router = new VueRouter({   routes: [     {       path: "/",       component: Home,       children: [         {           path: "create",           component: Modal,           props: {             component: Content           }         }       ]     }   ] });  

Since the modal is a child route of '/', the Home component needs to render the router-view:

<template>   <div>     Hi i'am home     <router-view />     <router-link to="/create">open modal</router-link>   </div> </template> 

And the App.vue needs to render the portal target, so the modal goes to the end of your content (it makes positioning the modal a lot easier):

<template>   <div id="app">     <img alt="Vue logo" src="./assets/logo.png" width="25%" />     <router-view />     <portal-target name="modal" />   </div> </template>  <script> export default {   name: "App", }; </script> 

And that's it

like image 70
Alykam Burdzaki Avatar answered Sep 21 '22 17:09

Alykam Burdzaki