How to display a route as a modal in Vue.js
Published: 2019-10-07 17:59:24

---
title: How to display a route as a modal in Vue.js
published: true
---

Hello everyone!

In this tutorial we are going to learn how to display a Vue route as a modal, similar to image links on Dribble.com or Google contacts. This format is very useful when you want to show information to the user without redirecting them to another page

![](https://github.com/charleswritescode/vue-samples-modal-route/raw/master/tutorial/screenshot4.png)

This tutorial assumes you are familiar with Vue.js. 

First lets create a basic vue project with vue-router

```vue-create $folder```

For this project I also installed faker.js to create dummy data for our contact list
```npm install --save faker```

Then I created the following files

***src/db.js (Mock database)***

```
import faker from 'faker'

const contacts = {}

for (let index = 0; index < 10; index++) {
    const id = "user_" + index
    contacts[id] = {
        id,
        name: `${faker.name.firstName()}  ${faker.name.lastName()}`,
        jobTitle: faker.name.jobTitle(),
        email: faker.internet.email(),
        phone: faker.phone.phoneNumber(),
    }
}

export default {
    contacts
}
```

***src/views/Contacts.vue (Contact list)***

```
<template>
  <div class="contacts">
    <h2>Contacts</h2>
    <div class="contact-list">
      <router-link
        tag="div"
        class="item"
        :to="`/contacts/${contact.id}`"
        v-for="contact in contacts"
        :key="contact.id"
      >
        <strong>{{contact.name}}</strong>
        <br />
        <span>{{contact.jobTitle}}</span>
      </router-link>
    </div>
  </div>
</template>

<script>
import db from "@/db.js";
export default {
  computed: {
    contacts() {
      return Object.values(db.contacts);
    }
  }
};
</script>

<style lang="scss" scoped>
.contact-list {
    .item {
        &:not(:last-child) {
            margin-bottom: 8px;
        }
        padding: 16px;
        border-radius: 4px;
        border: solid 1px #e2e2e2;
    }
}
</style>
```

***src/views/ContactInfo.vue***

```
<template>
  <div class="contact-info">
    <router-link to="../">X</router-link>
    <h3>{{contact.name}}</h3>

    <h4>Job Title</h4>
    <span>{{contact.jobTitle}}</span>
    3
    <h4>Email</h4>
    <span>{{contact.email}}</span>

    <h4>Phone</h4>
    <span>{{contact.phone}}</span>
  </div>
</template>

<script>
import db from "@/db.js";
export default {
  props: ["contactId"],
  data() {
    return {
      contact: ""
    };
  },
  created() {
    this.contact = db.contacts[this.contactId];
  }
};
</script>

<style lang="scss" scoped>
.contact-info {
    padding: 16px;
}
</style>
```

I also modified the `src/router.js` file to add a route for `/contacts` that points to the Contacts.vue component. I am also redirecting the root path to `/contacts`

![Changes to router.js](https://github.com/charleswritescode/vue-samples-modal-route/raw/master/tutorial/img1.png)

After making these changes we get this:
![Result](https://github.com/charleswritescode/vue-samples-modal-route/raw/master/tutorial/screenshot1.png)

If we click on a user the route will display a blank screen. To fix this we need to add a route for the ContactInfo component. We need to create the route as a child of the `/contacts` route. 

***src/router.js***

```
import ContactInfo from './views/ContactInfo.vue'
...
{
      path: '/contacts',
      component: Contacts,

      // ADDED
      children: [
        {
          path: ':contactId',
          component: ContactInfo,
          props: true
        }
      ]
    },
...
```

Next we need to add a `router-view` component to `Contacts.vue`

```
...
  <div class="contacts">
  ...
  ...
    <router-view></router-view>
  </div>
</template>
```
Now click a Contact and you will see this at the bottom of the screen:
![Result](https://github.com/charleswritescode/vue-samples-modal-route/raw/master/tutorial/screenshot2.png)

This is not exactly what we want. We need to make the router-view show as a modal. We have to make a few changes

Go to `Contacts.vue` and replace `<router-view></router-view>` with this

```
...
    <div v-if="showModal" class="modal-route">
      <div class="modal-content">
        <router-view></router-view>
      </div>
    </div>
...
```
We are moving router-view inside a "Modal" wrapper which will only be display when the `showModal` property is set to true

Then add this to `style` section
```
.modal-route {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  background: rgba($color: #000000, $alpha: 0.5);
  .modal-content {
    width: 50%;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: white;
  }
```

And finally in the `script` section, we add watcher for the $route property and create a `showModal` property inside our data. `showModal` is set to false to prevent the modal from being displayed when we first load the page.
```
...
 watch: {
    $route(newVal, oldVal) {
      this.showModal = newVal.meta && newVal.meta.showModal;
    }
  },
  data() {
    return {
      showModal: false
    }
  },
```
Every Vue component has a `$route` property that contains information about the current route. (More information on the `$route` object [Here](https://router.vuejs.org/api/#the-route-object)). By watching the `$route` property we can be notified when the current route changed.

Next open `src/router.js` and add a `meta` property to the /contacts/:contactId route
```
...
component: Contacts,
children: [
  {
    path: ':contactId',
    component: ContactInfo,
    props: true
    meta: {
      showModal: true
    }
  },
...
```
In Vue.js the `meta` property is used to pass additional information to the route. `meta` is not to be mistaken with the `props` property. More info on `meta` [here](https://router.vuejs.org/guide/advanced/meta.html)

Now click on a contact and you should see the modal
![](https://github.com/charleswritescode/vue-samples-modal-route/raw/master/tutorial/screenshot3.png)

The new route is now /contacts/user_0 and the contact info is displayed in the same page.

If you refresh the page you will see that the modal is not displayed even thought the route points to `/contacts/:contactId` The `router-view` modal is only displayed when `showModal` is set to true. The problem is that Vue does not call a watcher by default when a component is created and since `showModal` is set to false when the component is rendered, the modal is not visible. To fix this we need to refactor our `$route` watcher like this:

***src/Contacts.vue***
```
$route: {
      immediate: true,
      handler: function(newVal, oldVal) {
        this.showModal = newVal.meta && newVal.meta.showModal;
      }
}
```

The `handler` property is the function that is executed when a changes occurs to the property we are watching. `immediate:true` tells Vue to check the watched property `$route` when the component is created. More info on watched [here](https://vuejs.org/v2/guide/computed.html#Watchers)

Now refresh the page and the modal should be displayed properly.

I hope you enjoyed this tutorial. The full source code is available on [Github](https://github.com/charleswritescode/vue-samples-modal-route) ! And a demo is a working demo is available at http://friendly-brain.surge.sh