Conditional route in Vue.js - javascript

I have two different views that I'd like to show for the same path depending on whether a token is in LocalStorage or not. I could move the logic directly into the view itself, but I was curious to know whether there's a way to it in the Router.
Something like:
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "home",
component: function() {
if (...) {
return ViewA
} else {
return ViewB
}
}
},
]
});
I tried with the above code but didn't work. The app builds fine but none of the two views is shown.

A getter could be used for this, but, you will need to be sure to import both components:
import ViewA from '#/views/ViewA'
import ViewB from '#/views/ViewB'
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "home",
get component() {
if (...) {
return ViewA;
} else {
return ViewB;
}
}
},
]
});
In my notes, I have written "cannot find documentation on this" pertaining to the above. While not specifically related, however, it might be helpful to review using some information from https://stackoverflow.com/a/50137354/3261560 regarding the render function. I've altered what is discussed there using your example above.
component: {
render(c) {
if (...) {
return c(ViewA);
} else {
return c(ViewB);
}
}
}

I was answering the same question before and you can see it here.
Here is an example:
routes: [
{
path: '*',
beforeEnter(to, from, next) {
let components = {
default: [A, B, C][Math.floor(Math.random() * 100) % 3],
};
to.matched[0].components = components;
next();
}
},
... where A, B, C are components and they are randomly chosen every time the route changes. So in your case you can just alter beforeEnter logic to your needs and set any component you wish before routing to it.

Alright so I found a simple way to do this using the webpack lazy loading functionality in vue router with vuex store state property;
{
path: '/',
component: () => {
if (store.state.domain) {
return import(/* webpackChunkName: "app-home" */ '../views/AppHome.vue');
} else {
return import(/* webpackChunkName: "home" */ '../views/Home.vue');
}
}
},
With the above code, my home component is dynamically imported and used the route component depending on the value of domain property in my vuex store. Please note that you have to set up vuex store and import it in your router for this to work.
The solution in the question would have worked if you returned the component as an import.

Related

Vue router - how to have multiple components loaded on the same route path based on user role?

I have app where user can login in different roles, eg. seller, buyer and admin.
For each user I'd like to show dashboard page on the same path, eg. http://localhost:8080/dashboard
However, each user will have different dashboard defined in different vue components, eg. SellerDashboard, BuyerDashboard and AdminDashboard.
So basically, when user opens http://localhost:8080/dashboard vue app should load different component based on the user role (which I store in vuex). Similarly, I'd like to have this for other routes. For example, when user goes to profile page http://localhost:8080/profile app should show different profile component depending on the logged in user.
So I'd like to have the same route for all users roles as opposed to have different route for each user role, eg. I don't want user role to be contained in url like following: http://localhost:8080/admin/profile and http://localhost:8080/seller/profile etc...
How can I implement this scenario with vue router?
I tried using combination of children routes and per-route guard beforeEnter to resolve to a route based on user role. Here is a code sample of that:
in router.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import store from '#/store'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: Home,
beforeEnter: (to, from, next) => {
next({ name: store.state.userRole })
},
children: [
{
path: '',
name: 'admin',
component: () => import('#/components/Admin/AdminDashboard')
},
{
path: '',
name: 'seller',
component: () => import('#/components/Seller/SellerDashboard')
},
{
path: '',
name: 'buyer',
component: () => import('#/components/Buyer/BuyerDashboard')
}
]
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
in store.js:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
userRole: 'seller' // can also be 'buyer' or 'admin'
}
})
App.vue contains parent router-view for top-level routes, eg. map / to Home component and /about to About component:
<template>
<router-view/>
</template>
<script>
export default {
name: 'App',
}
</script>
And Home.vue contains nested router-view for different user's role-based components:
<template>
<div class="home fill-height" style="background: #ddd;">
<h1>Home.vue</h1>
<!-- nested router-view where user specific component should be rendered -->
<router-view style="background: #eee" />
</div>
</template>
<script>
export default {
name: 'home'
}
</script>
But it doesn't work because I get Maximum call stack size exceeded exception in browser console when I call next({ name: store.state.userRole }) in beforeEnter. The exception is:
vue-router.esm.js?8c4f:2079 RangeError: Maximum call stack size exceeded
at VueRouter.match (vue-router.esm.js?8c4f:2689)
at HTML5History.transitionTo (vue-router.esm.js?8c4f:2033)
at HTML5History.push (vue-router.esm.js?8c4f:2365)
at eval (vue-router.esm.js?8c4f:2135)
at beforeEnter (index.js?a18c:41)
at iterator (vue-router.esm.js?8c4f:2120)
at step (vue-router.esm.js?8c4f:1846)
at runQueue (vue-router.esm.js?8c4f:1854)
at HTML5History.confirmTransition (vue-router.esm.js?8c4f:2147)
at HTML5History.transitionTo (vue-router.esm.js?8c4f:2034)
and thus nothing is rendered.
Is there a way I can solve this?
You might want to try something around this solution:
<template>
<component :is="compName">
</template>
data: () {
return {
role: 'seller' //insert role here - maybe on `created()` or wherever
}
},
components: {
seller: () => import('/components/seller'),
admin: () => import('/components/admin'),
buyer: () => import('/components/buyer'),
}
Or if you prefer maybe a bit more neat (same result) :
<template>
<component :is="loadComp">
</template>
data: () => ({compName: 'seller'}),
computed: {
loadComp () {
const compName = this.compName
return () => import(`/components/${compName}`)
}
}
This will give you the use of dynamic components without having to import all of the cmps up front, but using only the one needed every time.
Such code retrieves component code only for a given role:
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";
import store from "../store";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "home",
component: () => {
switch (store.state.userRole) {
case "admin":
return import("../components/AdminDashboard");
case "buyer":
return import("../components/BuyerDashboard");
case "seller":
return import("../components/SellerDashboard");
default:
return Home;
}
}
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
One approach would be to use a dynamic component. You could have a single child route whose component is also non-specific (e.g. DashboardComponent):
router.js
const routes = [
{
path: '/',
name: 'home',
children: [
{
path: '',
name: 'dashboard',
component: () => import('#/components/Dashboard')
}
]
}
]
components/Dashboard.vue
<template>
<!-- wherever your component goes in the layout -->
<component :is="dashboardComponent"></component>
</template>
<script>
import AdminDashboard from '#/components/Admin/AdminDashboard'
import SellerDashboard from '#/components/Seller/SellerDashboard'
import BuyerDashboard from '#/components/Buyer/BuyerDashboard'
const RoleDashboardMapping = {
admin: AdminDashboard,
seller: SellerDashboard,
buyer: BuyerDashboard
}
export default {
data () {
return {
dashboardComponent: RoleDashboardMapping[this.$store.state.userRole]
}
}
}
</script>
You run into the Maximum call stack size exceeded exception because the next({ name: store.state.userRole }) will trigger another redirection and call the beforeEnter again and thus results in infinite loop.
To solve this, you can check on the to param, and if it is already set, you can call next() to confirm the navigation, and it will not cause re-direction. See code below:
beforeEnter: (to, from, next) => {
// Helper to inspect the params.
console.log("to", to, "from", from)
// this is just an example, in your case, you may need
// to verify the value of `to.name` is not 'home' etc.
if (to.name) {
next();
} else {
next({ name: store.state.userRole })
}
},
I faced the same problem (I use Meteor JS with Vue JS) and I found the way to do it with the render function to load different components on the same route. So, in your case it should be:
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";
import AdminDashboard from "../components/AdminDashboard";
import BuyerDashboard from "../components/BuyerDashboard";
import SellerDashboard from "../components/SellerDashboard";
import store from "../store";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "home",
component: {
render: (h) => {
switch (store.state.userRole) {
case "admin":
return h(AdminDashboard);
case "buyer":
return h(BuyerDashboard);
case "seller":
return h(SellerDashboard);
default:
return h(Home);
}
}
}
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
Note that this solution also works but only for the first time, if you enter again to that route, the last component loaded it will keep (you will need to reload the page). So, with the render function it always load the new component.
Vue Router 4 (Vue 3)
If you are using Vue Router 4 (usable only with Vue 3), one alternative solution is to use dynamic routing
This new feature allows us to remove/add routes on the fly.
// router.js
import { createRouter, createWebHistory } from 'vue-router'
import store from "../store";
import Home from "../views/Home.vue";
import About from "../views/About.vue";
// all routes independent of user role
const staticRoutes = [
{
path: "/",
name: "home",
component: Home,
},
{
path: "/about",
name: "about",
component: About,
},
]
const getRoutesForRole = (role) => {
// imlementation can vary - see the rest of the answer
}
// routes used at app initialization
const initialRoutes = [...staticRoutes, ...getRoutesForRole(store.state.userRole)]
const router = createRouter({
history: createWebHistory(),
routes: initialRoutes,
})
export default router
export const updateRoutesForRole = () {
// implementation can vary - see the rest of the answer
}
How to generate dynamic routes - getRoutesForRole
The implementation of course depends on many factors - how many routes (and also roles) do you have is probably most important.
With just 2 or 3 routes (and not many roles) it is just fine to use a static definition:
const routesPerRole = {
"admin": [
{
path: "/dashboard",
name: "dashboard",
component: () => import("../components/AdminDashboard.vue")
}, // more routes follow....
],
"seller": [
{
path: "/dashboard",
name: "dashboard",
component: () => import("../components/SellerDashboard.vue")
}, // more routes follow....
],
"buyer": [
{
path: "/dashboard",
name: "dashboard",
component: () => import("../components/BuyerDashboard.vue")
}, // more routes follow....
],
}
const getRoutesForRole = (role) => {
if(!role) return []
return routesPerRole[role]
}
If you have many routes and/or many roles, you probably want something more generic. First we need some good naming convention - for example lets say that we will organize our components in a directory structure like this: #/components/${role}/${componentName}.vue
Then we can use Webpacks dynamic import
const routeTemplates = [
{
path: "/dashboard",
name: "dashboard",
component: 'Dashboard'
},
]
const getRoutesForRole = (role) => {
if(!role) return []
const routesForRole = routeTemplates.map(route => ({
...route,
component: () => import(`#/components/${role}/${route.component}.vue`)
}))
return routesForRole
}
Note that thanks to how import() with dynamic expression works in Webpack this will make Webpack to create new JS chunk for each component in #/components folder which may be not what you want.
Easy fix is to move the "role dependent" components into it's own subfolder so instead of using #/components/admin/.... just use #/components/perRoleComponents/admin/.... and
import(`#/components/perRoleComponents/${role}/${route.component}.vue`)
Other solution is to use different import() statement for each role. This will also allow us to use Webpacks "magic comments" and for example force Webpack to pack all components for each role into single js chunk:
const routeTemplates = [
{
path: "/dashboard",
name: "dashboard",
component: 'Dashboard'
},
]
const getComponentLoader = (role, componentName) => {
switch(role) {
"admin": return () => import(
/* webpackChunkName: "admin-components" */
/* webpackMode: "lazy-once" */
`#/components/admin/${componentName}.vue`)
"seller": return () => import(
/* webpackChunkName: "seller-components" */
/* webpackMode: "lazy-once" */
`#/components/seller/${componentName}.vue`)
"buyer": return () => import(
/* webpackChunkName: "buyer-components" */
/* webpackMode: "lazy-once" */
`#/components/buyer/${componentName}.vue`)
}
}
const getRoutesForRole = (role) => {
if(!role) return []
const routesForRole = routeTemplates.map(route => ({
...route,
component: getComponentLoader(role, route.component)
}))
return routesForRole
}
How to update routes - updateRoutesForRole()
Easiest scenario is when each role has same set of routes and just wants to use a different component. In this case to switch the routes when role changes we can just use addRoute
Add a new route record to the router. If the route has a name and there is already an existing one with the same one, it removes it first.
export const updateRoutesForRole = () {
const role = store.state.userRole
const routesForRole = getRoutesForRole(role)
routesForRole.forEach(r => router.addRoute(r))
}
For more complicated scenarios where not all routes are available for all roles, previous routes (for previous active role - if any) must be removed 1st using removeRoute function. Also our getRoutesForRole() must be different. One solution is to use route meta fields
const routeTemplates = [
{
path: "/dashboard",
name: "dashboard",
component: 'Dashboard',
meta: { forRoles: ['admin', 'seller'] }
},
]
const getRoutesForRole = (role) => {
if(!role) return []
const routesForRole = routeTemplates
.filter(route => route.meta?.forRoles?.includes(role))
.map(route => ({
...route,
component: () => import(`#/components/${role}/${route.component}.vue`)
}))
return routesForRole
}
export const updateRoutesForRole = () {
const role = store.state.userRole
// delete previous 1st
router.getRoutes()
.filter(route => route.meta?.forRoles)
.forEach(route => router.removeRoute(route.name))
const routesForRole = getRoutesForRole(role)
routesForRole.forEach(r => router.addRoute(r))
}
Router v3 (for Vue 2)
Note that Router v3 (and earlier) was never designed with dynamic routing in mind. There is no removeRoute() function. There is a addRoute() so some of the scenarios described above could be probably possible but it currently (Router v3.5.3) does not work as described in the documentation
One way to solve this is to create three separate components DashboardForAdmin, DashBoardForSeller, and DashBoardForBuyer for three types of users.
Then use a mixin.js
export default {
data: function () {
return {
userType : "buyer"; // replace this with a function that returns "seller", "buyer", or "admin"
}
}
}
Create a Vue component DashboardContainer renders the correct dashboard component based on mixin return value
<template>
<div>
<div v-if="userType === 'admin'">
<DashboardForAdmin />
</div>
<div v-else-if="userType === 'buyer'">
<DashboardForBuyer />
</div>
<div v-else>
<DashboardForSeller />
</div>
</div>
</template>
<script>
import mixin from '#/mixin.js';
import DashboardForAdmin from '#/components/DashboardForAdmin.vue';
import DashBoardForSeller from '#/components/DashBoardForSeller.vue';
import DashBoardForBuyer from '#/components/DashBoardForBuyer.vue';
export default {
mixins: [mixin],
components: {
DashboardForAdmin, DashBoardForSeller, DashBoardForBuyer
},
};
</script>
Now you can add a single route for the DashboardContainer

Dynamic Routing and Component creation based on route

I want to have a couple of "overview" pages for sections my app, that will all be triggered on the root of that section.
so localhost/hi should display component HiOverview
localhost/he should display component HeOverview
as there are multiple of those, i want to avoid assigning the component to a const, then reusing it in a route. instead i want to handle all that in a single dynamic route.
BUT i'm struggling with the creation of the Components in the beforeEnter hook.
each route object expects a component... but i just want to decide the component depending on route. (sectionsWithOverview is a simple array of strings containing the names of routes where i want an overview displayed
const router = new Router({
linkActiveClass: 'active',
mode: 'history',
routes: [
{ path: '/:section',
component: Placeholder,
beforeEnter: (to, from, next) => {
const section = to.params.section
// how can i use this in the next() call?
// const View = () => import(/* webpackChunkName: 'sectionView' */ `Components/${section}/${section}Overview`)
if (sectionsWithOverview.includes(to.params.section)) {
next({ name: `${to.params.section}Overview` })
} else {
next()
}
},
}
can you guys help me? how can i conditionally assign a component onBeforeEnter, and then route to that exact Component?
it works if i declare each SectionOverview beforehand, but that makes my whole idea pointless.
Thanks for any help :)
I made something similar with a project but instead I used beforeRouteUpdate
Here is an example of how it works. On route.js simply define your dynamic route
const router = new Router({
linkActiveClass: 'active',
mode: 'history',
routes: [
{
path: '/:section',
component: Placeholder,
name: 'placeholder'
},
}
Then in your component (I assume Placeholder.vue) in your HTML add this line of code
<transition name="fade" mode="out-in">
<component :is="section" key="section"></component>
</transition>
then in your JS add the beforeRouteUpdate hook and define all your components that will match your route section param.
import he from './heOverview.vue'
import hi from './hiOverview.vue'
beforeRouteUpdate (to, from, next) {
// just use `this`
this.section = to.params.section
next()
},
components: {
he,
hi
},
data () {
return {
section: ''
}
}
So when a user navigate to localhost/he the heOverview.vue component will be loaded. The only thing you have to make sure is that the section param's value should match an specific view if not an error will be produced
If you need more info about how this work, read
https://v2.vuejs.org/v2/guide/components-dynamic-async.html
https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards

Change language on direct url input (VueJs)

I have implemented localisation with vue-i18n.
my main.js
import Vue from 'vue'
import { i18n } from './plugins/i18n'
import Cookie from "vue-cookie";
if (!Cookie.get('locale')) {
Cookie.set('locale', 'en', 1)
}
new Vue({
el: '#app',
router,
i18n,
template: '<App/>',
components: {App},
render: h => h(App),
mounted() {},
data: {
event: false
}
}).$mount();
my i18n.js plugin
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import enTranslations from '../../lang/en'
import slTranslations from '../../lang/sl'
import Cookie from 'vue-cookie'
Vue.use(VueI18n);
export const i18n = new VueI18n({
locale: Cookie.get('locale'),
fallbackLocale: 'en', // fallback option
messages: { en: enTranslations, sl: slTranslations}
});
My routes
{
path: '/:lang',
component: {
template: '<router-view></router-view>'
},
children: [
{
path: '',
name: 'Home',
component: Home
},
{
path: 'contact',
name: 'Contact',
component: Contact
}
]
}
And my switch language function in my navigation component
setLocale(locale) {
let selectedLang = locale.toLowerCase();
Cookie.set('locale', selectedLang, 1);
this.$router.push({name: this.$route.name, params: {lang: selectedLang}});
location.reload();
},
So far everything ok and working when I switch language via upper function setLocale(). The problem appears when user inputs url directly for example:
I have currently selected english language and then user visits page directly via url, let's say: localhost:8080/sl/contact
If I understand documentation correctly I should configure this in routes with beforeEnter function. So my current implementation looks like this.
beforeEnter: (to, from, next) => {
let selectedLang = to.params.lang.toLowerCase();
Cookie.set('locale', selectedLang, 1);
next();
},
But this doesn't do the trick, because it's only working on second reload.
So the cooke locale is set to correct language, but looks like them component code happens before so UI is still in old language. When I refresh again, then content of page is in correct language. How can I overcome this problem?
If you need any additional information's please let me know and I will provide. Thank you!
When you navigate from localhost:8080/sl/contact to localhost:8080/en/contact, the same **'Contact'**vue component instance will be reused. Since both routes render the same component,
Please refer to the documentation:
https://router.vuejs.org/guide/essentials/dynamic-matching.html#reacting-to-params-changes.
To re-render the contact component you could either watch the $route object or use in-component navigation guards beforeRouteUpdate to react to changes and then reload your component or any application logic you wish to execute.
To know further about in-component navigation guards please refer to this link https://router.vuejs.org/guide/advanced/navigation-guards.html#per-route-guard
Please try this,
Option 1:
watch:{
$route(to, from){
let selectedLang = to.params.lang.toLowerCase();
Cookie.set('locale', selectedLang, 1);
//reload your component
}
Option 2:
beforeRouteUpdate: (to, from, next) => {
let selectedLang = to.params.lang.toLowerCase();
Cookie.set('locale', selectedLang, 1);
next();
},

How to expose a component's data to child components in a router context? [duplicate]

Suppose I have a Vue.js component like this:
var Bar = Vue.extend({
props: ['my-props'],
template: '<p>This is bar!</p>'
});
And I want to use it when some route in vue-router is matched like this:
router.map({
'/bar': {
component: Bar
}
});
Normally in order to pass 'myProps' to the component I would do something like this:
Vue.component('my-bar', Bar);
and in the html:
<my-bar my-props="hello!"></my-bar>
In this case, the router is drawing automatically the component in the router-view element when the route is matched.
My question is, in this case, how can I pass the the props to the component?
<router-view :some-value-to-pass="localValue"></router-view>
and in your components just add prop:
props: {
someValueToPass: String
},
vue-router will match prop in component
sadly non of the prev solutions actually answers the question so here is a one from quora
basically the part that docs doesn't explain well is
When props is set to true, the route.params will be set as the component props.
so what you actually need when sending the prop through the route is to assign it to the params key ex
this.$router.push({
name: 'Home',
params: {
theme: 'dark'
}
})
so the full example would be
// component
const User = {
props: ['test'],
template: '<div>User {{ test }}</div>'
}
// router
new VueRouter({
routes: [
{
path: '/user',
component: User,
name: 'user',
props: true
}
]
})
// usage
this.$router.push({
name: 'user',
params: {
test: 'hello there' // or anything you want
}
})
In the router,
const router = new VueRouter({
routes: [
{ path: 'YOUR__PATH', component: Bar, props: { authorName: 'Robert' } }
]
})
And inside the <Bar /> component,
var Bar = Vue.extend({
props: ['authorName'],
template: '<p>Hey, {{ authorName }}</p>'
});
This question is old, so I'm not sure if Function mode existed at the time the question was asked, but it can be used to pass only the correct props. It is only called on route changes, but all the Vue reactivity rules apply with whatever you pass if it is reactive data already.
// Router config:
components: {
default: Component0,
named1: Component1
},
props: {
default: (route) => {
// <router-view :prop1="$store.importantCollection"/>
return {
prop1: store.importantCollection
}
},
named1: function(route) {
// <router-view :anotherProp="$store.otherData"/>
return {
anotherProp: store.otherData
}
},
}
Note that this only works if your prop function is scoped so it can see the data you want to pass. The route argument provides no references to the Vue instance, Vuex, or VueRouter. Also, the named1 example demonstrates that this is not bound to any instance either. This appears to be by design, so the state is only defined by the URL. Because of these issues, it could be better to use named views that receive the correct props in the markup and let the router toggle them.
// Router config:
components:
{
default: Component0,
named1: Component1
}
<!-- Markup -->
<router-view name="default" :prop1="$store.importantCollection"/>
<router-view name="named1" :anotherProp="$store.otherData"/>
With this approach, your markup declares the intent of which views are possible and sets them up, but the router decides which ones to activate.
const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true }
// for routes with named views, you have to define the props option for each named view:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
Object mode
const router = new VueRouter({
routes: [
{ path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }
]
})
That is the official answer.
link
Use:
this.$route.MY_PROP
to get a route prop

Unable to read Route Parameter in Angular 2

I have successfully implemented route parameter in Angular JS for my other components in same project and for the new component also I am following the same way but It's not working and I am unable to understand the problem in the code.
Below is the code of my routes file
import { Routes, RouterModule } from '#angular/router';
import { CustomerBillComponent } from '../components/customer_bill.component';
const routes: Routes = [
{ path: 'add-bill', component: CustomerBillComponent },
{ path: 'add-bill/:customer_reference', component: CustomerBillComponent },
];
export const routing = RouterModule.forRoot(routes);
(I tried using different routes also, but it didn't work)
Below is the code in My CustomerBillComponent.ts file
ngOnInit() {
//When I visit /#/add-bill/CR452152
let route_location = location['hash'].split('/')[1].toLowerCase();
console.log(route_location); //prints add-bill in Console
var customer_reference = this.route.snapshot.params['customer_reference'];
console.log(customer_reference); //prints undefined
}
Did I miss something
Thanks in advance!!!
I face almost the same problems. But the reason was different.
In my scenario, the lending page(Component Specified on routing) was different and I was trying to access the route params on the parent Route Component.
Below is the code to demonstrate my scenario:
home.module.routing.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
//other import statements...
const routes: Routes = [
{
path: 'home', component: HomeComponent,
children: [
{ path: 'buy/:mainType/:subType', component: BuyComponent, data: {} },
{ path: 'buy/:mainType', component: BuyComponent, data: { } },
{ path: '', redirectTo: 'buy', pathMatch: 'full' },
]
},
{ path: 'checkout', component: CheckoutCartComponent },
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class HomeRoutingModule { }
So, I had to access the RouteParam values in HomeComponent(Parent) and the Lending page was BuyComponent(Child Route of HomeComponent).
So, I was not getting values of route params using below code:
//Inside HomeComponent.ts
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
this.routeText = params['category'];
this.title = this.formatTitle(this.routeText);
});
}
As the lending page is BuyComponent, the above code will not work. Angular allows to access the route params in the above way only on the landing Component.
I tried a lot and finally got a solution to access the Route Params in parent route Component.
Below is the code to access the same:
//Inside HomeComponent.ts
const routeChildren = this.activatedRoute.snapshot.children;
if (routeChildren.length) {
//Your code here to assign route params to the Component's Data Member.
}
So, accessing this.activatedRoute.snapshot.children instead of this.route.params did the trick for me.
Hope this will help if someone lands here in search of the problem like me.
Best Regards.
You need to add ModuleWithProviders. It's a wrapper for module provider.
import {ModuleWithProviders} from '#angular/core';
export const routing: ModuleWithProviders = RouterModule.forRoot(router);
First try:
this.route.params.subscribe(
(params) => {
console.log(params);
}
)
And see what you get. If that doesn't work it's likely that you try to access a parent route's parameter, in which case you have to step up in the router tree in order to gain access to it.
You can do this with the .parent property, like such:
this.route.parent.params.subscribe(
(params) => {
console.log(params);
}
)
As many times as you need.

Categories