1

I don't understand why I'm getting the undesired result, running v2 vue.js.

I have a vue component in a single component file.

Basically the vue should render data (currently being imported from "excerciseModules" this is in JSON format).

It's dynamic so based on the url path it determines what to pull out of the json and then load it in the page, but the rendering is being done prior to this, and I'm unsure why. I've created other views that conceptually do the samething and they work fine. I dont understand why this is different.

I chose the way so I didn't have to create a ton of routes but could handle the logic in one view component (this one below).

Quesiton is why is the data loading empty (it's loading using the empty "TrainingModules" on first load, and thereafter it loads "old" data.

Example url path is "https...../module1" = page loads empty

NEXT

url path is "https..../module 2" = page loads module 1

NEXT

url path is "https..../module 1" = page loads module 2

//My route
{

        path: '/excercises/:type',
        name: 'excercises',
        props: {
        },
        component: () => import( /* webpackChunkName: "about" */ '../views/training/Excercises.vue')
    }

<template>
<div class="relatedTraining">
    <div class="white section">
        <div class="row">
            <div class="col s12 l3" v-for="(item, index) in trainingModules" :key="index">
                <div class="card">
                    <div class="card-content">
                        <span class="card-title"> {{ item.title }}</span>
                        <p>{{ item.excercise }}</p>
                    </div>
                    <div class="card-action">
                        <router-link class="" to="/Grip">Start</router-link>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
</template>

<script>
    console.log('script');
    let trainingModules; //when initialized this is empty, but I would expect it to not be when the vue is rendered due to the beforeMount() in the component options. What gives?
/* eslint-disable */
let init = (params) => {
    console.log('init');
    console.log(trainingModules);
    trainingModules = excerciseModules[params.type];
   

    //return trainingModules
    
}
import { getRandom, randomImage } from '../../js/functions';
import { excerciseModules } from '../excercises/excercises_content.js'; //placeholder for JSON
export default {
    name: 'excercises',
    components: {
    },
    props: {
    },
    methods: {
        getRandom,
        randomImage,
        init
    },
    data() {
        return {
            trainingModules,
        }
    },
    beforeMount(){
        console.log('before mount');
        init(this.$route.params);
    },
    updated(){
        console.log('updated');
        
    },
    mounted() {
        
        console.log('mounted');
        //console.log(trainingModules);
    }
}

</script>

1 Answer 1

3

I can walk you through a minimal working example that does what you are trying to accomplish.

The first thing you want to do, is to ensure your vue-router is configured correctly.

export default new Router({
  mode: "history",

  routes: [
    {
      path: "/",
      component: Hello
    },
    {
      path: "/dynamic/:type",
      component: DynamicParam,
      props: true
    }
  ]
});

Here I have a route configured that has a dynamic route matching with a parameter, often called a slug, with the name type. By using the : before the slug in the path, I tell vue-router that I want it to be a route parameter. I also set props: true because that enables the slug value to be provided to my DynamicParam component as a prop. This is very convenient.

My DynamicParam component looks like this:

<template>
  <div>
    <ul>
      <li v-for="t in things" :key="t">{{ t }}</li>
    </ul>
  </div>
</template>

<script>
const collectionOfThings = {
  a: ["a1", "a2", "a3"],
  b: ["b1", "b2"],
  c: [],
};

export default {
  props: ["type"],
  data() {
    return {
      things: [],
    };
  },
  watch: {
    type: {
      handler(t) {
        this.things = collectionOfThings[t];
      },
      immediate: true,
    },
  },
};
</script>

As you can see, I have a prop that matches the name of the slug available on this component. Whenever the 'slug' in the url changes, so will my prop. In order to react to those changes, I setup a watcher to call some bit of code. This is where you can make your fetch/axios/xhr call to get real data. But since you are temporarily loading data from a JSON file, I'm doing something similar to you here. I assign this data to a data value on the component whenever the watcher detects a change (or the first time because I have immediate: true set.

I created a codesandbox with a working demo of this: https://codesandbox.io/s/vue-routing-example-forked-zesye

Sign up to request clarification or add additional context in comments.

4 Comments

I appreciate you taking the time to provide a working example, thank you I got it working. From your example I'm of the understanding that I should use watch when I want to 'refresh' the renderer/vue based upon a change in some dataset etc? As an aside is this design optimal in vue? The only thing I could think of with in my limited time with vue is to create many routes to achieve the desired outcome.? Thanks again!
Like anything - it depends. The approach I described works really well for scenarios where you have completely dynamic data. For example, imagine an online store: you'd have a database with all the items - and that list is updated all the time and you don't want to redeploy every time a new item is available. Your route could look like products/:productId and the watch will fetch the individual product data to populate the page. If you have a smaller set of pages and you dont mind redeploying to add more, you can create components for the individual pages.
Great explanation thank you, the example replicates my scenario very closely.
Thanks. I copy the code and applied my project successfully. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.