When accessing the '/contact' route, I aim to maintain the existing view of the previous routes while displaying a modal window

When it comes to the design of my website, I have decided not to include a separate contact page. Instead, I want a modal to appear when the /contact link is clicked. However, I am facing two challenges:

a) If someone directly lands on '', I want the homepage view to display and the modal to automatically pop up.

b) If a visitor is already on the website and then decides to go to the /contact route, I want to maintain their current view (e.g. /about) and have the modal displayed on top of it.

I have been attempting to achieve this in a new Vue 2 installation using Vue router, but I am struggling to figure it out. I have been having difficulty finding the right resources through online searches.

Answer №1

Check out the code snippet below for a potential solution, even though demonstrating direct navigation to /contact may be a bit tricky.

Vue.use(VueRouter)

const contactGuard = function(to, from, next) {
  if (to.name === 'contact') {
    this.$root.$emit('modal', true)
    next(false)
  } else {
    next()
  }
}

const routes = [{
    path: '/',
    name: 'home',
    component: {
      template: `<div><p>Home Page</p></div>`,
      beforeRouteLeave: contactGuard
    }
  },
  {
    path: '/about',
    name: 'about',
    component: {
      template: `<div><p>About Page</p></div>`,
      beforeRouteLeave: contactGuard
    }
  },
  {
    path: '/contact',
    name: 'contact',
    beforeEnter: (to, from, next) => {
      if (from.path) {
        // we're coming from another page
        this.$root.$emit('modal', true)
        next(false)
      } else {
        // we've directly navigated to /contact
        next({
          replace: true,
          path: '/',
          query: {
            contact: true
          }
        })
      }
    }
  }
]

const router = new VueRouter({
  routes
})

router.beforeEach((to, from, next) => {
  next(vm => {
    if (to.query.contact) {
      vm.$root.$emit('modal', true)
    }
  })
})

new Vue({
  el: '#app',
  router,
  data() {
    return {
      modal: false
    }
  },
  mounted() {
    this.$on('modal', show => {
      this.modal = show
    })
  }
})
.modal-mask {
  position: fixed;
  z-index: 9998;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, .5);
  display: table;
  transition: opacity .3s ease;
}

.modal-wrapper {
  display: table-cell;
  vertical-align: middle;
}

.modal-container {
  width: 300px;
  margin: 0px auto;
  padding: 20px 30px;
  background-color: #fff;
  border-radius: 2px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .33);
  transition: all .3s ease;
  font-family: Helvetica, Arial, sans-serif;
}

.modal-header h3 {
  margin-top: 0;
  color: #42b983;
}

.modal-body {
  margin: 20px 0;
}

.modal-default-button {
  float: right;
}


/*
 * The following styles are auto-applied to elements with
 * transition="modal" when their visibility is toggled
 * by Vue.js.
 *
 * You can easily play with the modal transition by editing
 * these styles.
 */

.modal-enter {
  opacity: 0;
}

.modal-leave-active {
  opacity: 0;
}

.modal-enter .modal-container,
.modal-leave-active .modal-container {
  -webkit-transform: scale(1.1);
  transform: scale(1.1);
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app">
  <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <a class="navbar-brand" href="#">Foobar</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item">
          <router-link class="nav-link" :to="{ name: 'home' }">Home</router-link>
        </li>
        <li class="nav-item">
          <router-link class="nav-link" :to="{ name: 'about' }">About</router-link>
        </li>
        <li class="nav-item">
          <router-link class="nav-link" :to="{ name: 'contact' }">Contact</router-link>
        </li>
      </ul>
    </div>
  </nav>
  <div class="container">
    <router-view></router-view>
  </div>
  <transition name="modal">
    <div class="modal-mask" v-if="modal">
      <div class="modal-wrapper">
        <div class="modal-container">

          <div class="modal-header">
            <slot name="header">
              default header
            </slot>
          </div>

          <div class="modal-body">
            <slot name="body">
              default body
            </slot>
          </div>

          <div class="modal-footer">
            <slot name="footer">
              default footer
              <button class="modal-default-button" @click="$root.$emit('modal', false)">
                OK
              </button>
            </slot>
          </div>
        </div>
      </div>
    </div>
  </transition>
</div>

Answer №2

Hey there, I wanted to share an alternative approach. This method maintains routes without converting to queries and does not depend on jQuery.

Essentially, it involves leveraging the beforeEnter function to adjust route information.

Rather than defining the component in the routes in the traditional way, I store it in the meta section. This simplifies copying from from to to.

For example, the /contact route utilizes a showContact meta to determine when to display the overlay.

const routes = [
  { path: '/', meta: { component: Home } },
  { path: '/bar', meta: { component: Bar } },
  {
    path: '/contact',
    meta: { showContact: Contact, component: null },
    beforeEnter: (to, from, next) => {
      if (from.matched[0]) {
        to.meta.component = from.matched[0].components.default;
      }
      next();
    },
  },
];

Instead of using <router-view/>, I opt for

<component v-bind:is="$route.meta.component"></component>
to render the component.

To display the contact form:

<component v-if="$route.meta.showContact" v-bind:is="$route.meta.showContact"></component>

Check out this CodeSandbox example, free of any styling:

https://codesandbox.io/s/3v947j8y05

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Display the country code according to the option chosen by the user in the dropdown menu

To enhance user experience, I am implementing a feature where the user can select their country from a drop-down list and then have the corresponding country code displayed in a text field for easy entry of their phone number. Below is the list of countri ...

An error occurred while trying to load the resource in the Redux-Saga: connection refused

Utilizing axios allows me to make calls to the backend server, while redux-saga helps in managing side effects from the server seamlessly. import {call, put, takeEvery} from "redux-saga/effects"; import {REQUEST_FAILED, REQUEST_SUCCESS, ROOT_URL, SUBMIT_U ...

Enable Row Editing with a Click in Material Table

Utilizing the material-table library, I am implementing a feature to enable table rows to be editable upon double-click. The goal is for clicking on a row to trigger the same action as clicking the edit button located in the actions column on the leftmost ...

Having trouble generating an image with JavaScript

I am currently working on incorporating an image onto a webpage using JavaScript. Surprisingly, even the alert('This function works!') is not displaying anything! What could be causing this issue? Please assist! <!DOCTYPE html> <html> ...

How can I open a new window, redirect the current one, and bring focus to the new window using JavaScript?

Trying to troubleshoot a problem I'm having with the following setup: - Using SAP Portal, I am launching an HTML page containing this code. - The goal is for the HTML page to open a new window. - Once the new window opens, the original HTML page ...

Scrollbar in an HTML selection tag

Is there a way to add a scroll bar to an HTML select box without using JavaScript? Alternatively, is there a JavaScript library that can achieve this behavior? Also, I'm looking for a redesign of the interface where I have two select boxes and items ...

Javascript promise failing to deliver

As a beginner in the world of JavaScript development, I am excited to be part of the stackoverflow community and have already gained valuable insights from reading various posts. Currently, I am facing an issue where I need to load a file, but due to its ...

Having trouble getting Vue Components Styles to take effect

This is the main container component: <template> <div class="main-content"> <slot /> </div> </template> Next, we have the topbar component: <template> <!-- top bar with back component --> < ...

Troubleshooting problems during Vue setup

Just diving into Vue development and hitting a roadblock. Here's what I've done so far: I followed the installation guide on the Vue 3 documentation, which can be found at the following link: https://v3.vuejs.org/guide/installation.html#npm I ...

Troubleshooting issue with jQuery subtraction not functioning as expected

Everything seems to be functioning correctly except for the subtraction operation. function add_culture(ele) { total=parseInt($('#total_price').val()); culture_price=parseInt($('#culture_price').val()); $(& ...

Iterate through the call feature repeatedly, ensuring that each call has a different iteration number assigned to a variable within the

I have a situation where I need to call a certain feature (which has validations) multiple times within a loop. Currently, my code successfully calls the feature 3 times. * def xxx = """ function(times){ for(i=0;i<times ...

Showing the date in AngularJSAngularJS can be used to

I have a view set up in AngularJS and I'm attempting to show the current date in a formatted way. My initial thought was to use <span>{{Date.now() | date:'yyyy-MM-dd'}}</span> to display the current date. ...

I'm a beginner when it comes to Android WebView and incorporating JavaScript into my projects

Struggling to make my Android app work with JavaScript, even though I've enabled it. Despite all the research I've done suggesting it should work, it's not. Any assistance would be greatly appreciated. Below is my Java code: protected ...

How do I customize the rounding and color of selected dates in Vue Tailwind Datapicker?

I am looking to give the selected data a more square rounding. Additionally, I need help with specifying colors in the tailwind.config file that will be compatible with this component. The vtd-primary color currently does not work. https://i.sstatic.net/S ...

Having trouble with JavaScript in a project I'm trying to replicate

For my coding practice, I am working on a project where clicking on the images should change the main product displayed along with its color. However, nothing happens when I click on the products. Can anyone point out what I might be doing wrong? Here is ...

How can I transfer a MongoDB collection to an EJS file in the form of a sorted list?

I have successfully displayed the collection as a json object in its own route, but now I want to show the collection in a list under my index.ejs file (I'm still new to ejs and MongoDB). Below is the code that allows me to view the json object at lo ...

Bootbox Dialog Form

Looking to implement a functionality where a Bootbox dialog pops up with an "OK" button. Upon clicking the "OK" button, it should initiate a POST request, sending back the ID of the message to acknowledge that the user has read it. The Bootbox dialog fun ...

An overview on adding a new element to an array of objects in AngularJS

I have a feature on my website where users can create via points. Each user starts with one point, and if they want to add more, they can click "add" to insert a new object in the array with an empty value. The user then has the option to input a new value ...

Unchecking and checking the radio button is necessary in order for it to function properly

Today, I'm puzzled by the odd behavior of my radio buttons in a pixel drawer project. In order for the radio button to function properly, I have to uncheck it and then recheck it. The pixel drawer allows me to change colors and sizes using these radio ...

What is the best way to combine two arrays and generate a new array that includes only unique values, similar to a Union

Here are two arrays that I have: X = [ { "id": "123a", "month": 5, "markCount": 75 }, { "id": "123b", "month": 6, "markCount": 85 ...