Reputation: 708
I have a vue router with two components,a list and a detail view, with a link back to the list view. On the same page I have a list of the same data that is shown in the list-view component.
The data is fetched via ajax, and as such is not ready when the router-view is drawn. When the data is ready however, the non-router list is updated, but the router view is not.
How do I communicate to the router view that it should redraw with new data?
If I click on an item in the non-router list, the router-view changes to the details component as expected, and if I then click the "show list" it changes back to the list-component, but this time it is populated with the right data.
I have created a js-fiddle that contains the relevant code: https://jsfiddle.net/pengman/jkwvphf9/2/ (It fakes the ajax by using setTimeout, but the effect is the same)
Html code:
<div id="app">
Router-view:
<router-view class="view"></router-view>
<br>
Unrouted list:
<div class="list-group">
<router-link v-for="plante in planter" class="list-group-item" :to="{ name: 'plante', params: { nummer: plante.Nummer }}">{{ plante.Navn }} | </router-link>
</div>
</div>
<template id="plante-listing-template">
<ul>
<li v-for="plante in planter">
{{ plante.Navn }} <router-link :to="{ name: 'plante', params: { nummer: plante.Nummer }}">Vis</router-link>
</li>
</ul>
</template>
<template id="plante-detail-template">
<div>
plante detail template:
<h3>{{ plante.Navn }}</h3>
<router-link to="/">Show List</router-link>
</div>
<br>
</template>
Javascript code:
var PlanteListing = {
template: '#plante-listing-template',
data: function () {
return {
planter: this.$parent.planter
}
},
watch: {
'$route'(to, from) {
// vi skal opdatere data, saa vi skal beregne igen
this.planter = this.$parent.planter;
},
'dataloaded'() {
this.planter = this.$parent.planter;
}
}
};
var PlanteDetail = {
template: '#plante-detail-template',
data: function () {
var parent = this.$parent;
var nummerFromRoute = this.$route.params.nummer;
//console.log(nummerFromRoute);
var filtered = this.$parent.planter.filter(function (item) {
return (item.Nummer == nummerFromRoute) ? item : false;
});
return {
plante: filtered[0]
}
},
watch: {
'$route'(to, from) {
// vi skal opdatere data, saa vi skal beregne igen
var nummerFromRoute = this.$route.params.nummer;
var filtered = this.$parent.planter.filter(function (item) {
return (item.Nummer == nummerFromRoute) ? item : false;
});
this.plante = filtered[0];
},
}
};
var router = new VueRouter({
mode: 'hash',
base: window.location.href,
routes: [
{ path: '/', component: PlanteListing },
{ name: 'plante', path: '/:nummer', component: PlanteDetail }
]
});
var app = new Vue({
router,
data: {
planter: []
},
components: { PlanteListing: PlanteListing },
methods: {
getJson: function () {
var self = this;
/* Real code:
$.getJSON("content/planter.json", function (param) {
this.planter = param;
}.bind(this));
*/
/* Simulation code: */
setTimeout(function(){self.planter = [ { "Nummer": "0", "Navn": "Bertha Winters" }, { "Nummer": "1", "Navn": "Jeannie Small" }, { "Nummer": "2", "Navn": "Mckay Joyner" }, { "Nummer": "3", "Navn": "Janelle Banks" }, { "Nummer": "4", "Navn": "Bray Moran" }, { "Nummer": "5", "Navn": "Hooper Schwartz" }]; console.log('data loaded')}, 500);
}
},
created: function () {
this.getJson();
}
}).$mount('#app');
Upvotes: 1
Views: 1551
Reputation: 82459
Typically you do not want to have a component reach out of itself to get data (as you are doing with this.$parent.planter
). Instead, you want to pass it props. To that end, I've modified your code a bit.
The first thing is I upgraded your vue-router
to the latest version. This allows you to use the props
argument on routes.
var router = new VueRouter({
mode: 'hash',
base: window.location.href,
routes: [
{ path: '/', component: PlanteListing },
{ name: 'plante', path: '/:nummer', component: PlanteDetail, props: true }
]
});
Secondly, you are using planter
in all your routes, so I have provided it as a property on the router-view
.
<router-view class="view" :planter="planter"></router-view>
This allows us to clean up your component routes and add the data they need as props.
var PlanteListing = {
template: '#plante-listing-template',
props:["planter"]
};
var PlanteDetail = {
template: '#plante-detail-template',
props:["planter", "nummer"],
data: function () {
var filtered = this.planter.filter(item => item.Nummer == this.nummer);
return {
plante: filtered[0]
}
}
};
There is no need to tell the router to redraw; because the data are props, Vue just takes care of that for us.
Here is your updated fiddle.
Upvotes: 2