1
votes

I'm trying to create a single page vue.js application using vue-router. The default route (/) should be a list of links to the other pages (like a landing page). So far, all the other pages are dialogs for different scenarios. I want to make creating new dialogs as straight forward as possible, so I've created a base-dialog page which sets up the generic dialog look, while leaving the details up to the specific route. There are three sections: basic settings, logging settings, and advanced settings. Basic settings will be required for each scenario, logging settings is the same for each scenario, and advanced settings are optional. I'm using named router-views to load basic and advanced settings.


Previous Research

I've based my solution on this thread.


Code Samples

DialogPage.vue

<template>
  <div>
    <div id="basic-options" class="options">
      <router-view name="basicView" basic="true"/>
    </div>
    <div id="logging-options" class="alt-options">
      <!-- Custom components needed for logging options. This renders properly. -->
    </div>
    <div id="advanced-options" class="alt-options">
      <router-view name="advancedView" basic="false"/>
    </div>
  </div>
</template>

{Scenario}.vue

<template>
  <div>
    <!-- custom components to set up basic dialogs for {Scenario} -->
  </div>
</template>

{Scenario}Advanced.vue is the same as {Scenario}.vue except using different children in the div.

ScenarioSelector.js

/* Import Scenario Here */
import ScenarioA from '@/components/Scenarios/A'
import ScenarioAAdvanced from '@/components/Scenarios/AAdvanced'
import ScenarioB from '@/components/Scenarios/B'
import ScenarioBAdvanced from '@/components/Scenarios/BAdvanced'

/* Add them to the list */
const components =
{
    ScenarioA,
    ScenarioAAdvanced,
    ScenarioB,
    ScenarioBAdvanced
}

/* Don't change anything here */
export default
{
    functional: true,
    props: [
        {
            name: 'scenario',
            type: String
        },
        {
            name: 'basic',
            type: Boolean,
            default: true
        }
    ],
    render (createElement, context) {
        var scenario = context.props.scenario
        console.log('Log anything, please')
        if (context.props.basic) {
            scenario += 'Advanced'
        }
        return createElement(components[scenario], context.data, context.children)
    }
}

Relevant section of router/index.js

export default new Router({
  routes: [
    /* Other routes */,
    {
      path: "/dialog/:scenario",
      component: DialogPage,
      props: true,
      children:[
        {
          path: "*",
          components: { basicView: ScenarioSelector, advancedView: ScenarioSelector },
          props: { basicView: true, advancedView: true }
        }
      ]
    }
  ]
}

The Problem

It doesn't seem to be entering the render function of ScenarioSelector. Nothing gets logged. I have gotten it to enter that function once or twice, but I'm not sure what I did differently to make that happen, and even when it does happen there are no props being set.


Other Things I've Tried Alternate routes:

export default new Router({
  routes: [
    /* Other routes */,
    {
      path: "/dialog/",
      component: DialogPage,
      props: true,
      children:[
        {
          path: "/:scenario",
          components: { basicView: ScenarioSelector, advancedView: ScenarioSelector },
          props: { basicView: true, advancedView: true }
        }
      ]
    }
  ]
}

For this one, the links from the landing page (which are just /dialog/{Scenario}) don't do anything.

export default new Router({
  routes: [
    /* Other routes */,
    {
      path: "/dialog/",
      component: DialogPage,
      props: true,
      children:[
        {
          path: "ScenarioA",
          components: { basicView: ScenarioA, advancedView: ScenarioAAdvanced }
        },
        {
          path: "ScenarioB",
          components: { basicView: ScenarioB, advancedView: ScenarioBAdvanced }
        }
      ]
    }
  ]
}

Again, in this case the links do nothing.


Edit

I mentioned earlier in the post that I wasn't sure what I'd done differently to make that code execute. I just changed * to / in the child path, and it executes. Sample below:

export default new Router({
  routes: [
    /* Other routes */,
    {
      path: "/dialog/:scenario",
      component: DialogPage,
      props: true,
      children:[
        {
          path: "/",
          components: { basicView: ScenarioSelector, advancedView: ScenarioSelector },
          props: { basicView: true, advancedView: true }
        }
      ]
    }
  ]
}
1

1 Answers

1
votes

I have just got this working properly. There were two issues.

  1. This one I already mentioned in my edited. I should have used "/" as the path for the children, rather than "*". I thought "*" would have been the safer choice, since it wouldn't matter what the last part of the path was, but it seems to not work (if anyone could elaborate on why, that would be greatly appreciated). Please see the Edit section of the question for the relevant code section.
  2. The second issue was my prop definition in ScenarioSelector.js. The answer to this question explains what I did wrong. If I wanted to use prop validation, my props should have been an object. Relevant code sample below:

/* ... */
export default
{
    functional: true,
    props: {
        scenario: String,
        basic: {
            type: Boolean,
            default: true
        }
    },
    render (createElement, context) {
        var scenario = context.props.scenario
        console.log('Log anything, please')
        if (context.props.basic) {
            scenario += 'Advanced'
        }
        return createElement(components[scenario], context.data, context.children)
    }
}

After fixing both of these issues, the props values are bound correctly and the log is outputted to the dev tools console.