Router Vue is not transfering from.params to route - vue.js

so i have sth like this:
in router:
{
path: '/feature',
name: 'CustomFeature',
component: CustomFeature,
pathToRegexpOptions: { strict: true },
meta: {
title: Custom features,
scrollToTop: true,
}
}
in product component (template):
<a #click="createNewFeature">go</a>
and then:
createNewFeature() {
this.$router.push('/feature#new')
}
and in my CustomFeature component:
beforeRouteEnter(to, from, next) {
console.log(from) // - here is problem
...
it should show me that is going from "product site" route
i tried changing
<a #click="createNewFeature">go</a>
to just
<router-link to="/feature#new">go</router-link>
or
<router-link :to="{ path: '/feature#new' }">go</router-link>
but it doesnt work i tried to add children to '/feature' path in router but i dont know how to do it properly (and if it is a case)

Related

My vue.js nav will not navigate to other pages, just reloads the same page

new to Vue js so hopefully it is simply something I have missed.
I have a navbar component, which generates a list of nav items like below:
<template>
<div class="nav-section">
<nav>
<span class="logo">D & E</span>
<ul>
<li v-for="item in items" :key="item.id">
<a :href="item.href">{{ item.text }}</a>
</li>
</ul>
</nav>
</div>
</template>
<script>
import "./navbar.scss";
export default {
name: 'NavBar',
components: {
},
props: {
},
data() {
return {
items: [
{
id: 1,
href: "/homepage",
text: "Home"
},
{
id: 2,
href: "/about",
text: "The Wedding"
},
{
id: 3,
href: "/story",
text: "Our story"
},
{
id: 4,
href: "/travel",
text: "Travel & Stay"
},
{
id: 5,
href: "/response",
text: "RSVP"
}
]
};
},
methods: {
},
}
</script>
however, when i am clicking each link, this just looks like it reloads the homepage, so I can never actually see a new page (which is obviously not what I want).
Have I missed anything glaringly obvious with this?
To add, I have not got vue router installed in the project, not sure how this can be done or if it is even needed?
VueJS is an SPA, so you're not using traditional a tags to move from page to page (as you do in Wordpress realm for example, which is MPA).
Maybe give a read to that one for more details.
If you want to move from page to page, you need to use Vue router as you guessed.
You need to define the routes in a /router/index.js file with something like this
import Vue from "vue";
import VueRouter from "vue-router";
import CustomersName from "../views/CustomersName.vue";
import HomeView from "../views/HomeView.vue";
import AboutView from "../views/AboutView.vue";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "index",
component: HomeView,
},
{
path: "/about",
name: "about",
component: AboutView,
},
{
path: "/customers/:name",
name: "customers-name",
component: CustomersName,
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
});
export default router;
And use router-link to move to that given page
<router-link to="/about">about page</router-link>
I've just updated one of my github repo with a working configuration.
Clone the project locally and inspect how it works if you want more details.

VueJS: How to make a nested router-view always render one of its routes?

TL:DR;Is it possible to make the router-view display a component without being on that component route ?
I am trying to imitate a carousel effect using router-view inside a child component.
The problem is that if I don't click on a router-link the router-view displays nothing.
I want to make on of the router-link be active when no other is in order to force the router-view to always display something.
App.vue with the top router-view:
<template>
<div id="app">
<router-view />
</div>
</template>
Router index.js:
const routes = [
{
path: "/",
name: "LandingPage",
component: LandingPage,
children: [
{
path: "/icons",
name: "Icons",
component: () => import(/* webpackChunkName: "about" */ "../components/portfolio/Icons.vue"),
},
],
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
scrollBehavior(to, savedPosition) {
if (to.hash) {
return {
selector: to.hash,
behavior: "smooth",
// offset: { x: 0, y: 75 }
};
} else {
return savedPosition;
}
},
});
LandingPage.vue:
<template>
<div class="page">
<Home></Home>
<About></About>
<Portfolio></Portfolio>
<Contact></Contact>
</div>
</template>
Portfolio.vue with the second router-view:
<template>
<section id="portfolio">
<ul>
<li v-for="slide in slider" :key="slide.path">
<router-link :to="`/${slide.link}`">{{ slide.text }}</router-link>
</li>
</ul>
<router-view />
</section>
</template>
As you can see I have only one route, which is / for the top router-view. This will render LandingPage.
I use hashes to navigate to the components inside LandingPage like so: <router-link :to="{ path: '/', hash: #${link.path} }">
I am trying to make the router-link :to="/icons" active and the Icons component render inside Portfolio's router-view when no other link from Portfolio is active.
It's important for it to remain active only inside Portfolio, because I have a Navbar with other router-link which go to various hashes inside LandingPage.
Is this even possible ?
If I understood, you want to show Icon when the route is '/'.
To define a default sub-route you need to have a route with an empty value (path:'').
Now if you don't want to change path use the 'alias' mechanism.
const routes = [
{
path: "/",
name: "LandingPage",
component: LandingPage,
children: [
{
path: "/icons",
alias: '',
name: "Icons",
component: () => import(/* webpackChunkName: "about" */ "../components/portfolio/Icons.vue"),
},
],
},
];
If alias doesn't meet your needs, define your sub-route twice(One by empty path second by '/icons')
You can also define /icons as the main route:
const routes = [
{
path: "/icons",
name: "LandingPage",
component: LandingPage,
children: [
{
path: "",
name: "Icons",
component: () => import(/* webpackChunkName: "about" */ "../components/portfolio/Icons.vue"),
},
],
},
];

nested router with lazy load not work propertly

I am new to Vue and want to navigate Product child routes, but it do not work & get NotFound page instead.
So my question is how to make it properly.
Or can someone give some details. Thanks
Online Editor
index.js
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/products',
component: () => import('../views/ProductPage.vue'),
children: productRouter
},
{
path: '/**',
component: NotFound
}
]
product.js
const productRouter = [
{
path: '',
name: 'products',
component: ProductPage
},
{
path: 'product/:id',
name: 'ProductDetails',
component: ProductDetails
},
{
path: '**',
component: NotFound
}
]
There are some little mistakes leading to your unexpected result.
In product.js router you should not prefix again with products since it is already in the scope of the /products route. The NotFound route is also not needed in this definition since the parent's NotFound already matches the same route patterns. You can rewrite the product router definition like below :
const productRouter = [
{
path: ':id',
name: 'ProductDetails',
component: ProductDetails
}
]
Then, in ProductList.vue, you should rewrite your router-link as below :
<router-link :to="`/products/${item.id}`"> {{ item.description }} </router-link>
Finally, in ProductPage.vue, you are missing the <router-view></router-view> needed to render your child routes as explained in the vue router documentation.. You could rewrite it like below :
<template>
<div id="productPage">
<h1>This is an Product Page</h1>
<ProductList :items="products"> </ProductList>
<router-view></router-view>
</div>
</template>

Update the parent data when user navigates to a specific route path

I'm new in VueJs, trying to set up a web application with Vue-route, and want to update the <header> style when user navigates to a specific URL, whether using "URL bar" directly or "navigation bar". In this case, we have a parent component that contains height_status data and some <router-links> on template.
I've done the "navigation bar" part with $emit technique and it works well but then I've tried to use it on created lifecycle hook in order to update the header whenever the /home route is created but event listener will not reach the parent_component.
How can I solve this? Is there a better way to do that?
Please see the code below:
Parent_component.vue
<template>
<div id="app">
<router-link to="/home" #height_size_ctrl="change_height">Home</router-link>
<router-link to="/about">About us</router-link>
<router-link to="/contact">Contact us</router-link>
<header :class="height_status ? 'head-h-s' : 'head-h-m'"></header>
<router-view/>
</div>
</template>
<script>
export default {
name: "Parent_component"
},
data() {
return {
height_status: false
}
},
methods: {
change_height(h) {
this.height_status = h
}
}
}
</script>
router.js
Vue.use(Router)
export default new Router({
routes: [
{
path: '/home',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: about
},
{
path: '/contact',
name: 'contact',
component: contact
}
]
})
home.vue
<template>
<h1>hello</h1>
</template>
<script>
export default {
name: 'home',
created: function(){
return this.$emit("height_size_ctrl", true)
}
}
</script>
You could also change the router:
router.js
{
path: '/home',
name: 'home',
component: Home,
meta: {
headerClass: 'head-h-s'
}
}
In your component
Parent_component.vue
computed: {
headerClass() {
return this.$route.meta.headerClass
}
}
Now headerClass is available in the template.
<header :class="headerClass"></header>
why don't you try class binding on route or route name something like:
<div :class="{'height_status': this.$route == '/home'}">Header</div>
or
<div :class="{'height_status': this.$route.name == 'Home'}">Header</div>
As #kcsujeet said, class binding is the good way we can do this. In this case we need to look at the condition this.$route.path. if value is equal to the /home select 'head-h-m, otherwise select .head-h-s.
<header class="head-sec" :class=" this.$route.path == '/home' ? 'head-h-m' : 'head-h-s'">
Also we're able to access other route defined properties using this.$route. I suggest take a look at the router.js file.
routes: [
{
path: '/home',
name: 'home',
component: Home
}

Vue Router moves to route but loads wrong component

I have the following router config:
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'notselected',
component: PackageUnselected
},
{
path: '/package/:id',
children: [
{ path: 'meta', name: 'packageMeta', component: ViewPackageMeta },
{ path: 'readme', name: 'packageReadme', component: PackageReadme },
{ path: 'docs', name: 'packageDocs', component: PackageDocs },
{
path: 'playground',
name: 'packagePlayground',
component: PackagePlayground
}
]
},
{
path: '/about',
name: 'about',
component: About
},
{
path: '*',
redirect: '/'
}
]
});
And when I'm at the root route it correctly identifies the route name as notselected. When I route to any of the "/package/[id]" routes though it continues to load the PackageUnselected component instead of the appropriate route (aka, ViewPackageMeta, PackageDocs, etc.).
Now at the point in the DOM where I want the route to insert the route's component I have the following template:
<v-tab-item v-for="item in tabs" :id="'tab-item-' + item" :key="item" exact>
item: {{item}}
<router-view :selectedPackage="selected"></router-view>
</v-tab-item>
And because I have installed vuex-router-sync it's easy to see the route state at any given time. So when clicking on the route that should load PackageDocs:
But the component view window of vue-devtools looks like this:
the highlighted area shows that NO component has been loaded into the tabs. I then tried adding a component to the definition of the parent route /package/:id:
{
path: '/package/:id',
component: Packages,
children: [
{ path: 'meta', name: 'packageMeta', component: ViewPackageMeta },
{ path: 'readme', name: 'packageReadme', component: PackageReadme },
{ path: 'docs', name: 'packageDocs', component: PackageDocs },
{
path: 'playground',
name: 'packagePlayground',
component: PackagePlayground
}
]
},
I then had to create the world simplest component for Packages:
<template>
<view-router-view></view-router-view>
</template>
This results in the following:
Hmmm. Can't figure out what to do next. Anyone have any pointers?
When I route to any of the "/package/[id]" routes though it continues
to load the PackageUnselected component instead of the appropriate
route (aka, ViewPackageMeta, PackageDocs, etc.).
That is the correct behavior of the vue-router.
Children can only be loaded when URL paths are:
/package/[id]/meta
/package/[id]/readme
/package/[id]/playground
/package/[id]/docs
Parent path may not have component defined if you have configured redirect option and your user, who opens /package/[id] will be redirected to your default path (could be anything).
Lets move to the next part of your question...
<v-tab-item v-for="item in tabs" :id="'tab-item-' + item" :key="item" exact>
item: {{item}}
<router-view :selectedPackage="selected"></router-view>
</v-tab-item>
You don't need to create here 4 different <router-view> tags, you just need one where all your children components will display html code.
<v-tab-item v-for="item in tabs" :id="'tab-item-' + item" :key="item" exact></v-tab-item>
<router-view></router-view>
Now you will have only one router-view and it's the default one. When user clicks on any of your tabs you just need to this.$router.push a new path on #click-event in Packages component. That's it.
I have created a simple example (codepen) to demonstrate how this task can be solved:
Vue.use(VueRouter);
// Components
let MetaPackages = {
mounted() { console.log('Mounted MetaPackages...'); },
template: `<div>MetaPackages...</div>`,
};
let DocsPackages = {
mounted() { console.log('Mounted DocsPackages...'); },
template: `<div>DocsPackages...</div>`,
};
let ReadmePackages = {
mounted() { console.log('Mounted ReadmePackages...'); },
template: `<div>ReadmePackages...</div>`,
};
let Packages = {
mounted() { console.log('Mounted Packages... ' + this.$route.path); },
template: '<div>Packages (parent) screen...<br/><router-view></router-view></div>',
};
// Router
const router = new VueRouter({
mode: 'hash',
routes: [
{
path: "/packages/:id",
component: Packages,
children: [
{path:"meta", component: MetaPackages},
{path:"docs", component: DocsPackages},
{path:"readme", component: ReadmePackages}
]
}
]
});
// Vue instance
const vm = new Vue({
el: '#app',
router,
components: {Packages, MetaPackages, DocsPackages, ReadmePackages}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.2/vue-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<router-link to="/packages/100/meta">Meta</router-link>
<router-link to="/packages/100/docs">Docs</router-link>
<router-link to="/packages/100/readme">Readme</router-link>
<hr/>
<router-view></router-view>
</div>