title: Vue-Router Dynamic Components
body: <p>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.</p>
  
  <hr>
  
  <p><strong>Previous Research</strong></p>
  
  <p>I've based my solution on <a href="https://forum.vuejs.org/t/possible-or-advisable-to-have-dynamic-components-in-vue-router/16116" rel="nofollow noreferrer">this thread</a>.</p>
  
  <hr>
  
  <p><strong>Code Samples</strong></p>
  
  <p>DialogPage.vue</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;template&gt;
    &lt;div&gt;
      &lt;div id="basic-options" class="options"&gt;
        &lt;router-view name="basicView" basic="true"/&gt;
      &lt;/div&gt;
      &lt;div id="logging-options" class="alt-options"&gt;
        &lt;!-- Custom components needed for logging options. This renders properly. --&gt;
      &lt;/div&gt;
      &lt;div id="advanced-options" class="alt-options"&gt;
        &lt;router-view name="advancedView" basic="false"/&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/template&gt;</code></pre>
  </div>
  </div>
  </p>
  
  <p>{Scenario}.vue</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;template&gt;
    &lt;div&gt;
      &lt;!-- custom components to set up basic dialogs for {Scenario} --&gt;
    &lt;/div&gt;
  &lt;/template&gt;</code></pre>
  </div>
  </div>
  </p>
  
  <p>{Scenario}Advanced.vue is the same as {Scenario}.vue except using different children in the div.</p>
  
  <p>ScenarioSelector.js</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>/* 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)
      }
  }</code></pre>
  </div>
  </div>
  </p>
  
  <p>Relevant section of router/index.js</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>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 }
          }
        ]
      }
    ]
  }</code></pre>
  </div>
  </div>
  </p>
  
  <hr>
  
  <p><strong>The Problem</strong></p>
  
  <p>It doesn't seem to be entering the <code>render</code> function of <code>ScenarioSelector</code>. 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.</p>
  
  <hr>
  
  <p><strong>Other Things I've Tried</strong>
  Alternate routes:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>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 }
          }
        ]
      }
    ]
  }</code></pre>
  </div>
  </div>
  </p>
  
  <p>For this one, the links from the landing page (which are just /dialog/{Scenario}) don't do anything.</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>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 }
          }
        ]
      }
    ]
  }</code></pre>
  </div>
  </div>
  </p>
  
  <p>Again, in this case the links do nothing.</p>
  
  <hr>
  
  <p><strong>Edit</strong></p>
  
  <p>I mentioned earlier in the post that I wasn't sure what I'd done differently to make that code execute. I just changed <code>*</code> to <code>/</code> in the child path, and it executes. Sample below:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>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 }
          }
        ]
      }
    ]
  }</code></pre>
  </div>
  </div>
  </p>