darinreid
darinreid

Reputation: 21

VueJS and vue-router: view data does not update when using v-link

I am trying to link between VueJS components using vue-router's v-link. When a link is clicked, the URL is updated, but the view data does not update unless the page is manually refreshed.

Some context for this example: a Tour has many Tour Objects, and Tour Objects need to link to previous/next Tour Objects.

Here's the route that represents a Tour Object:

'/tours/:tourId/objects/:objectId': {
    name: 'tourObject',
    component: tourObjectComponent
}

Full example:

var App = Vue.extend({});

var tourObjectData = [
    { id: "1", name: "Object A" },
    { id: "2", name: "Object B" },
    { id: "3", name: "Object C" },
    { id: "4", name: "Object D" },
    { id: "5", name: "Object E" },
];

var tourComponent = Vue.extend({
    template: '#tourComponent',
    data: function() {
    	return {
        	objects: [],
        };
    },
    created: function() {
    	this.objects = tourObjectData;
    },
});

var tourObjectComponent = Vue.extend({
	template: '#tourObjectComponent',
    data: function() {
    	return {
            currIndex: null,
        	currObject: {},
            prevObject: {},
            nextObject: {},
        };
    },
    created: function() {
        this.currIndex = this.getCurrIndex();
    	this.currObject = this.getCurrObject();
        this.prevObject = this.getPrevObject();
        this.nextObject = this.getNextObject();
    },
    methods: {
        
        // Get current object index within tour objects
        getCurrIndex: function() {
            for (var i = 0; i < tourObjectData.length; i++) {
            	if (tourObjectData[i].id === this.$route.params.objectId) {
                	return i;
                }
            }
        },
        
        // Get current object
    	getCurrObject: function() {
            return tourObjectData[this.currIndex];
        },
        
        // Get previous object
        getPrevObject: function() {
			var prevIndex = this.currIndex > 0 ? 
                this.currIndex - 1 : 
            	tourObjectData.length - 1;
            
            return tourObjectData[prevIndex];
        },
        
        // Get next object
        getNextObject: function() {
            var nextIndex = this.currIndex < tourObjectData.length - 1 ?
                this.currIndex + 1 : 0;
            
            return tourObjectData[nextIndex];
        },
    },
});

var router = new VueRouter();

router.redirect({
    
    // Start on Tour 1
	'/': '/tours/1'
});

router.map({
    
    // Tour
	'/tours/:tourId': {
    	name: 'tour',
        component: tourComponent
    },
    
    // Object within tour
    '/tours/:tourId/objects/:objectId': {
    	name: 'tourObject',
        component: tourObjectComponent
    }
});

router.start(App, '#app');
<script src="https://cdn.jsdelivr.net/vue/0.12.10/vue.js"></script>
<script src="https://rawgit.com/vuejs/vue-router/dev/dist/vue-router.js"></script>

<script type="x-template" id="tourComponent">
    <h1>Tour</h1>
    <ul>
        <li v-repeat="objects">
            <a v-link="{name: 'tourObject', params: {tourId: 1, objectId: id}}">{{name}}</a>
        </li>
    </ul>
</script>

<script type="x-template" id="tourObjectComponent">
    <a v-link="{name: 'tour', params: {tourId: 1}}">Back to Tour</a>
    <h1>{{currObject.name}}</h1>
    <ul>
        <li><a v-link="{name: 'tourObject', params: {tourId: 1, objectId: prevObject.id}}">Previous Tour Object: {{prevObject.name}}</a></li>
        <li><a v-link="{name: 'tourObject', params: {tourId: 1, objectId: nextObject.id}}">Next Tour Object: {{nextObject.name}}</a></li>
    </ul>
</script>

<div id="app">
    <router-view></router-view>
</div>

Upvotes: 2

Views: 4413

Answers (2)

Luna
Luna

Reputation: 1178

For vuejs ^2, you can watch the route and trigger a change like this (in my case I had username parameter in my user routes):

watch:{
    '$route' (to, from) {
        if (to.params.username !== from.params.username) {
            //update whatever
        }
   }
},

Dynamic Route Matching from documentation

Upvotes: 3

Fran&#231;ois Romain
Fran&#231;ois Romain

Reputation: 14393

From the doc, (and help from @svevil on the gitter channel):

route: {
    data(transition) {
        transition.next(DataObjectForCurrentRoute);
    }
}

Also, you can use computed properties, like so:

var App = Vue.extend({});

var tourObjectData = [
    { id: "1", name: "Object A" },
    { id: "2", name: "Object B" },
    { id: "3", name: "Object C" },
    { id: "4", name: "Object D" },
    { id: "5", name: "Object E" },
];

var tourComponent = Vue.extend({
    template: '#tourComponent',
    data: function() {
      return {
        };
    },
    computed: {
      objects: function() {
          return tourObjectData;
      }
    },
});

var tourObjectComponent = Vue.extend({
  template: '#tourObjectComponent',
    data: function() {
      return {
            currIndex: null,
          currObject: {},
            prevObject: {},
            nextObject: {},
        };
    },
    computed: {
      currIndex: function() { 
        for (var i = 0; i < tourObjectData.length; i++) {
          if (tourObjectData[i].id === this.$route.params.objectId) {
            return i;
          }
        };
      },
      currObject: function() { 
        return tourObjectData[this.currIndex];
      },
      prevObject: function() { 
        var prevIndex = this.currIndex > 0 ? 
          this.currIndex - 1 : 
          tourObjectData.length - 1;
        
        return tourObjectData[prevIndex]; 
      },
      nextObject: function() { 
        var nextIndex = this.currIndex < tourObjectData.length - 1 ?
            this.currIndex + 1 : 0;
        
        return tourObjectData[nextIndex]; 
      },
    },
});

var router = new VueRouter();

router.redirect({
    
    // Start on Tour 1
  '/': '/tours/1'
});

router.map({
    
    // Tour
  '/tours/:tourId': {
      name: 'tour',
        component: tourComponent
    },
    
    // Object within tour
    '/tours/:tourId/objects/:objectId': {
      name: 'tourObject',
        component: tourObjectComponent
    }
});

router.start(App, '#app');
<script src="https://cdn.jsdelivr.net/vue/0.12.10/vue.js"></script>
<script src="https://rawgit.com/vuejs/vue-router/dev/dist/vue-router.js"></script>

<script type="x-template" id="tourComponent">
    <h1>Tour</h1>
    <ul>
        <li v-repeat="objects">
            <a v-link="{name: 'tourObject', params: {tourId: 1, objectId: id}}">{{name}}</a>
        </li>
    </ul>
</script>

<script type="x-template" id="tourObjectComponent">
    <a v-link="{name: 'tour', params: {tourId: 1}}">Back to Tour</a>
    <h1>{{currObject.name}}</h1>
    <ul>
        <li><a v-link="{name: 'tourObject', params: {tourId: 1, objectId: prevObject.id}}">Previous Tour Object: {{prevObject.name}}</a></li>
        <li><a v-link="{name: 'tourObject', params: {tourId: 1, objectId: nextObject.id}}">Next Tour Object: {{nextObject.name}}</a></li>
    </ul>
</script>

<div id="app">
    <router-view></router-view>
</div>

Upvotes: 0

Related Questions