How to change Vuetify tabs together with vue-router programmatically - vue.js

How to change Vuetify tabs together with vue-router
I use vuetify tabs and router see eg. How to use Vuetify tabs with vue-router
In this sample exist two child component Foo and Bar.
I would like to change active tab and route from Foo or Bar component .
This is simplified example. I have the standard Vue structure (main.js, App.vue, Foo.Vue, Bar.vue)
I can change only router via this.$router.replace
Thanks.
JS
const Foo = {
template: '<div>Foo component!</div>'
};
const Bar = {
template: '<div>Bar component!</div>'
};
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar },
];
const router = new VueRouter({ routes });
new Vue({
el: '#app',
router,
});
HTML
<v-app dark>
<v-tabs fixed-tabs>
<v-tab to="/foo">Foo</v-tab>
<v-tab to="/bar">Bar</v-tab>
</v-tabs>
<router-view></router-view>
</v-app>

Add the replace directive to your v-tab:
<v-tab to="/foo" replace>Foo</v-tab>
The key is in the question you linked:v-tab is a wrapper for router-link. Adding the replace prop to a router-link tells it to call router.replace() instead of router.push() (from the API Reference).

Related

Can I directly pass a label for a named route to<router-link>?

Say in my router.js I have something like this:
const routes = [
{
path: '/',
name: 'home',
label: 'Start',
component: Home
}
]
Then where I render my router link, I'd like to be able to use the alternate label property declared above, instead of manually entering it, and to avoid defining it somewhere else. I tried the bit below but it does not work (it works for the 'path' property though)
<router-link :to="{name: 'home'}">{{ this.$router.label }}</router-link>
EDIT: I found that (obviously!) this.$router refers to the current, active route.
For now at least, this is my solution:
In router.js (or /router/index.js in my case) declare the routes with labels as indicated in the original question. And export both the routes and the router object.
const routes = [
{
path: '/',
name: 'home',
label: 'Start',
component: Home
}
...
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export { router as default, routes };
In main.js import both variables and store routes in a way you can retrieve them anywhere.
import router, { routes } from '#/router'
Vue.prototype.routes = routes
new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount('#app')
Where you want to "render" the route links (in my case a navbar layout), do this (using vuetify here):
<v-app-bar app color="secondary" dark>
<v-btn v-for="route in routes" :to="{name: route.name}" key='route.name' text rounded :exact="true">
{{ route.label }}
</v-btn>
</v-app-bar>
I'm sure this can be improved probably using Vuex (which I'm still studying about).
UPDATE
Found a much better solution, that don't require the routes export/import and its assignment to Vue.prototype.routes = routes. Simply do this in the component where you want to use the routes data with labels and all. The template piece (v-btn etc) remains the same.
<script>
export default {
name: 'LayoutNav',
data() {
return {
routes: this.$router.options.routes
};
}
};
</script>

Why component in the vue-router routes makes no difference

I have an App component and it renders fine. It's basically a component comprising two components.
App (Vue component):
1. Navigation // a menu bar with menu items
//like <router-link to="/">Home</router-link>
//like <router-link to="/contact">Contact</router-link>
2. Library // a component listing books.
I want to add another component Contact which I tried adding using vue-router, so I use the above navigation component. However, the routes don't seem to affect anything at all. What am I doing wrong?
My main.js file
const Contact = {
template: '<div>Contact Us</div>'
}
const routes = [
{
path: '/',
component: App // any change here also does not make any difference!!!
},
{
path: '/contact',
component: Contact, // this or any component doesnt make any difference!!!
}
];
const router = new VueRouter({
routes,
});
new Vue({
render: h => h(App),
router,
}).$mount('#app')

VueJS Router prevent back on certains router-link's

Building PWA app with VueJS and I have tabs like navigation component. But instead of show/hide content, navigation is done through Vue Router. Side effect of this navigation is "back" button behavior, every navigation action is logged in browser history, after I visit 4 tabs, and if I want to go back to actual page which was before page with tabs, I need to press "back" 4 or more times (depends on how many times I navigated trough tabs).
What I want to do is something like this:
<router-link no-history="true" to="tab1">Tab1</router-link>
<router-link no-history="true" to="tab2">Tab2</router-link>
<router-link no-history="true" to="tab3">Tab3</router-link>
Of course, I don't want to do it globally. If this even possible?
You need to use router.replace.
From Vue Documentation :
It acts like router.push, the only difference is that it navigates without pushing a new history entry, as its name suggests - it replaces the current entry.
In your case, you would just need to add the replace attribute to your router-link tag :
<router-link to="tab3" replace>Tab3</router-link>
You can find more informations about replace on Vue programmatic navigation doc
add replace to your router-link to avoid stacking routes on the navigation history :
Vue.config.productionTip = false;
Vue.config.devtools = false;
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<h5>Navigate between routes then click "previous"</h5>
<button #click="$router.go(-1)">Previous</button>
<p>
<router-link to="/foo" replace>Go to Foo</router-link>
<router-link to="/bar" replace>Go to Bar</router-link>
</p>
<router-view></router-view>
</div>

Route to another page using Vue

I have the following code in my template:
<router-link to="/page1">Go to Page1</router-link>
Vue part:
const Page1 = { template: '<div>Hello Page1</div>' }
const routes = [
{ path: '/page1', component: Page1 },
]
const router = new VueRouter({
routes
})
var app = new Vue({
router,
el: '#app',
}).$mount('#app')
I want the Page1 component to be a HTML page like page1.html instead of "Hello Page1". Should I have
<router-view> </router-view>
on page1.html? How can I do that?
I don't quite understand your question. You are using Vue Router, which integrates with Vue's way of building Single Page Applications. Yet, you want to show a normal html page instead?

Vue-router component reusing

I would like to know how can I stop component reusing in Vue-router.
I'm building a simple page application and I am unable to update data after clicking the same link twice.
Is it possible to somehow force reloading or what are the best practices in my situation?
Use the key attribute on router-view set to current url. It's built in, so no need to write any code.
<router-view :key="$route.fullPath"></router-view>
Vue Router reuses the same component therefore the mounted hook won't be called. As stated in the documentation:
The same component instance will be reused [...] the lifecycle hooks of the component will not be called.
If you want to update the data you have two options:
Watch the $route object
const User = {
template: '...',
watch: {
'$route' (to, from) {
// react to route changes...
}
}
}
Use the beforeRouteUpdate navigation guard
const User = {
template: '...',
beforeRouteUpdate (to, from, next) {
// react to route changes...
// don't forget to call next()
}
}
For a more detailed explanation you can check the section Reacting to Param Changes of the Vue Router documentation: https://router.vuejs.org/guide/essentials/dynamic-matching.html#reacting-to-params-changes.
One way to do this is to put a key on the router-view and append a timestamp querystring to your router-link
const Home = {
template: '<div>Home</div>',
created() {
console.log('This should log everytime you click home.');
},
};
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/', component: Home },
]
});
new Vue({
router,
el: '#app',
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<router-link :to="`/?q=${Date.now()}`">/home</router-link>
<router-view :key="$route.fullPath"></router-view>
</div>
One reason not to do it this way is because it'll force rerenders on components that you may want to be reused such as on routes like
/posts/1
/posts/2