Using Vue: Dynamically pass components to router-view within dynamically loaded components

For a specific URI, I am looking to display a different layout on the same route by using different components based on whether the user is on mobile or desktop. I want to avoid cluttering the PageCommon (layout component) with route path checks.

In the app, there is a main component responsible for the layout, featuring various router-views where different components are loaded for each page URI. This is a standard route setup.

{
    path: '',
    component: PageCommon,
    children: [
      {
        path: '',
        name: 'Home',
        components: {
          default: Home,
          header: Header,
          'main-menu': MainMenu,
          'page-content': PageContent,
          footer: Footer,
          'content-footer': ContentFooter
        }
      },

Once a component is loaded, I cannot change the route components property. Therefore, I attempted to create a wrapper and dynamically pass the components.

 {
    path: 'my-view',
    name: 'My_View',
    component: () => import('@/components/MyView/ViewWrapper')
  },

Within 'components/MyView/ViewWrapper':

    <page-common v-if="isMobile">
        <my-mobile-view is="default"></my-mobile-view>
        <main-menu is="main-menu"></main-menu>     
    </page-common>    
    <page-common v-else>
        <my-desktop-view is="default"></my-desktop-view>
        <header is="header"></header>    
        <main-menu is="main-menu"></main-menu>    
        <footer is="footer"></footer> 
    </page-common>    

</template>

Although I expected the components within the page-common block to be replaced with the appropriate ones, Vue simply loads the page-common component with empty router-views. Any suggestions on how to handle this?

I have already experimented with using the :is property to load different components, but I encounter difficulties in informing the parent to use a specific component for a particular page. Here is the code snippet for that:

<template>
    <component :is="myView"></component>    
</template>
<script>
import DesktopView from "@/components/MyView/DesktopView";
import MobileView from "@/components/MyView/MobileView";
export default {
    name: 'MyView', 
    components: {
        DesktopView,
        MobileView,
    },
    data(){
        return {
            myView: null,
            isMobile: this.detectMobile()
        }
    },
    methods : {
        getViewComponent() {
            return this.isMobile ? 'mobile-view' : 'desktop-view';
        }
    },
    created() {
        this.myView = this.getViewComponent();
    }
}
</script>

I could apply this approach to each of the PageCommon router views, creating a separate component for each to achieve the same functionality, but it does not seem like an optimal solution.

Answer №1

When it comes to handling top level logic in your Vue.js application, a computed method is the key. Make sure to define this method in your App.vue file and include the <router-view> in both the DesktopView and MobileView components.

// App.vue

<template>

    <component :is="myView"></component>   
 
</template>

<script>

import DesktopView from "@/components/MyView/DesktopView";
import MobileView from "@/components/MyView/MobileView";

export default {

    name: 'MyView', 

    components: {
        DesktopView,
        MobileView,
    },

    computed: {
     
      myView() {

        return this.detectMobile() ? 'mobile-view' : 'desktop-view';

      }

   }

}
</script>

To optimize your application further, consider implementing code splitting with dynamic components. This allows you to load components as needed, improving performance for mobile users. You can achieve this by setting up dynamic imports for layouts in your MyView component and registering them globally in main.js.

// main.js

import LoadingDesktopComponent from '@/components/LoadingDesktopComponent '

Vue.componenet('desktop-view', () => ({
  component: import('@/components/MyView/DesktopView'),
  loading: LoadingDesktopComponent // Displayed while loading the Desktop View
})

// LoadingDesktopComponent .vue

<template>

  <div>
    Optimizing for Desktop, Please wait.
  </div>

</template>

<script>

export default {

  name: 'loading-component'

}

</script>

By structuring your routing logic to process only when <router-view> is available, you can delay the presentation of Vue Router. For instance, you can show a loading screen before displaying the relevant content within :is that contains <router-view>.

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

summoning the iframe from a separate window

In my current setup, I have a link that passes a source to an iframe: <a href='new.mp4' target='showVideo'></a> <iframe src='sample.jpg' name='showVideo' ></iframe> However, what I would lik ...

Click on the text within a paragraph element

Is there a way to retrieve the selected text or its position within a paragraph (<p>)? I'm displaying a text sentence by sentence using a Vue.js loop of paragraphs. <p class="mreadonly text-left mark-context" v-for="line in ...

Restricting the Vue for-loop results to display only the current item in use

Currently, I am utilizing a for-loop to retrieve all of my posts, followed by employing a partial to obtain a list of all the usersThatUpvoted on that post. <div v-for="p in posts" style="padding: 16px"> <div> &l ...

How can you extract elements from a JSON array into separate variables based on a specific property value within each element?

In the following JSON array, each item has a category property that determines its grouping. I need to split this array into separate JSON arrays based on the category property of each item. The goal is to extract all items with the category set to person ...

Steps for assigning values to a JavaScript array using its indices

Question: Dynamically creating keys in javascript associative array Typically, we initialize an array like this: var ar = ['Hello', 'World']; To access its values, we use: alert(ar[0]); // Hello However, I am looking to assign ...

Fetching and displaying JSON objects in a Rails view

I have implemented a search functionality on my Rails application. The Search controller is responsible for fetching spaces based on a query in the model, and then returning them as JSON. In order to retrieve this data, I am utilizing $.getJSON within a vi ...

Stop unauthorized pages from hijacking login cookies

I have a website called where users can create their own HTML pages accessible through the link if the username is "USR" and project is "PROJECT". However, there is a security concern... Currently, I store users' login tokens as cookies. But what ...

Problem encountered with a form element generating additional input fields upon click of a specific button

My goal is to create a button that dynamically adds email input fields to a form titled "Add Another Email". I have a function in place to trigger this action upon clicking the button, but unfortunately, nothing happens when the button is clicked. Surprisi ...

Obtain the refined information from a UiGrid table

Is there a way to loop through the filtered rows in an uigrid? I am aware that we can get the filtered rows using the following code: var filteredData = $scope.gridApi.core.getVisibleRows($scope.gridApi.grid); However, I need to iterate through it and cr ...

Having trouble with jQuery events not triggering properly after dynamically inserting elements using an ajax request?

It's strange that all my jQuery events become unresponsive after an AJAX call. When I use a load function, once the JSP reloads, none of the events seem to work properly. Any suggestions? Below is the code that triggers the function call: $('#p ...

How to temporarily change CSS color for 5 seconds using JavaScript and incorporate an easing effect?

Regarding this query: JavaScript - Modifying CSS color for 5 seconds Here is a live example of the solution: http://jsfiddle.net/maniator/dG2ks/ I am interested in adding an easing effect to the transition, gradually making the color fully opaque and t ...

Issue with the Material UI theme module enhancement feature not functioning as expected

I've been researching the MUI documentation, blogs, and various posts on Stackoverflow, but despite my efforts, I can't seem to get my vscode intellisense/typescript to recognize the changes I've made. These are fairly straightforward modif ...

Acquiring the markers, however the latitude and longitude are both null - vue.js

I have been working on displaying markers on a map. When I fetched the data, everything seemed fine in Vue DevTools. The `this.markers` property also contains the data. However, to my surprise, the values for `lat` and `lng` inside the markers are showing ...

Using a data() object in Vue to fill out form fields efficiently

My data retrieval process from mongodb involves obtaining the data and transferring it to the client side using the following approach: error_reporting(E_ALL); ini_set('display_errors', '1'); require '../vendor/autoload.php'; ...

Avoid reactivating focus when dismissing a pop-up menu triggered by hovering over it

I am currently utilizing @material-ui in conjunction with React. I have encountered the following issue: In my setup, there is an input component accompanied by a popup menu that triggers on mouseover. Whenever the menu pops up, the focus shifts away from ...

Encountering a Material UI error: Incorrect hook usage when combining create-react-library with MUI

After transitioning from Material Ui v3 to v4 on a create-react-library project, I encountered an issue. This particular project serves as a dependency for other projects in order to share components. However, when attempting to display a material-ui compo ...

Update an existing item or add a new one if it is not already present

I am attempting to create a functionality similar to canva.com, where users can select images from the sidebar and drop them anywhere in the "div", allowing multiple images with individual positions. However, when I use setState(prevState=>{return [...p ...

What is the method for determining the size of a WeakMap?

I am working with a WeakMap that looks like the following: let newObj = new WeakMap(); let key1={"a":1}; let key2={"b":2}; let key3={"c":3}; newObj.set(key1,"value1"); newObj.set(key2,"value2"); newObj.set( ...

Error: The JS Exception has not been handled, as it is stating that 'undefined' is not an object when evaluating 'global.performance.now' in react-native-tvOS

I am currently working on a React-Native-tvOs app and despite following all the instructions from the react-native-tvOs GitHub page, I keep encountering an error when running the default template app. Even after running the script provided on the GitHub re ...

"How can I extract father's details by clicking on a button

After clicking, I need to access the parent element. Here is the HTML code I have: <button mat-icon-button (click)="download($event)"> The generated HTML code is as follows: <button _ngcontent-wsc-c153="" mat-icon-button=&q ...