Vue Router 2.0 and Modals


#1

Hello all, wondering if I could get some help on structuring something in my app.

I have a component that lists a bunch of items, and I would like to be able to open a modal for each. In Vue 1 I had a single modal component and would open it by broadcasting/dispatching an event and pass the item through to the modal.

However in Vue 2 I don’t have broadcasting/dispatching available, and I’m using the router. I did look into named views, but wasn’t sure if that’s the direction to go.

One other factor: I would like to be able to navigate to a url and have the modal open automatically for specific items, which means I either need to pass a hash or query string.

Can someone give some advice on how I should proceed? Thank you


Vue2 modal with URL
Modal with vue-router dynamic parent
#2
const route = [
  { 
    path: '/items', 
    component: Items,
    children: [
      { path: ':id', component: ItemModal, name: 'itemModel' }
    ]:
  },
]

Items.vue

<template>
  <table>
    <!-- you item list -->
    <tr><td>
      <router-link :to="{name: 'itemModal', params: {id: item.id}}">See item 1</router-link>
    </td></tr>
  </table>
  <router-view>
    <!-- here the ItemModal component will be rendered -->
  </router-view>
</template>

ItemModal.vue

<template>
  <modal> <!-- some generic modal component, wrapping a CSS modal -->
    <h1>{{item.name}}</h1>
   <button @click="$router.go(-1)">close</button>
  </modal>
</template>

<script>
export default {
  data() {
    return {
      item: null
    }
  },
  created() {
    // use $route.params.id to get the item for that ID from whereever you have stored all the items.
    this.item = getItemFromSomeWhere()
  }
}
</script>

#3

Hey, just following up here… Thank you for your advice @LinusBorg

I can’t imagine where I’d be without the help of people like you. Thank you!


#4

Hi @LinusBorg I have a question regarding this.

Im building an e-commerce site where almost every route (around 15) need to have this child route modal. This means I have to add <router-view> to all my components and also add children to all my routes.

{
        path: '/',
        name: 'app',
        component: Home,
        children: [
            {   path: '/modal/products/:id/:slug?',
                component: ProductModal,
                name: 'productModal'
            }
        ]
    },

I guess I can loop over my routes object and push the child route to the children array and just add the <router-views> to the components but was wondering if theres a better way?

Also I wonder, if a user is coming from a link outside the website he should be redirected to the product link instead of a modal, for that I was thinking of using the beforeEach hook like:

router.beforeEach((to, from, next) => {
    if ( from.name == null && to.name == "productModal" ) { 
        router.push({ name: 'productPage', params: { id: to.params.id, slug: to.params.slug }})
    } else {
        next();
    }
});

Does this sound like a reasonable approach?


#5

I was wrong about this. I thought the children was only matched for the route the users currently at so I could add the same child for every route but it was not how it worked. I could only make my model work for the home route since thats the first one matched.


#6

@LinusBorg @jschutt
Hi guys, im trying to implement this too, however I get an error that “items” is no defined during render

//I thought i could pass a list of objects in 
this.item = getItemFromSomeWhere()
//like this 
this.item = this.modals

Any help with what i am doing wrong is much appreciated.


#7

Thank you, LinusBorg, for this information. I have been looking for an elegant way to use modals in a new VueJS application, and this works really well for me.


#8

Hey guys, this works, but since the route is changing now, it has the odd effect of hiding the current content of the page. Typically when showing a modal, you want it on TOP of what ever the existing content is.

How can we make the existing content stay in place?


#9

Heads up that modal is misspelled as model if you are copying this code (name: ‘itemModel’).