Deeply nested Angular routes - javascript

A the root of my app I have a "demo" route to a module that handles all the demos on the site:
{
path: 'demo',
canActivate: [AuthGuardService],
loadChildren: './demo/demo.module#DemoModule'
}
Then, in the demo module's routing module I have all the demos, some of which are also modules, such as
{
path: 'splitviews',
loadChildren: './splitviews/splitviews.module#SplitviewsModule'
}
Which is a module of demos of types of "Splitviews", components with 2 named route outlets: 1 for the left nav and 1 for the content:
<app-header class="site-header"></app-header>
<div class="site-content"></div>
<div [ngClass]="containerType"
class="splitview-wrapper">
<div class="row">
<div class="col-sm-2"">
<router-outlet name="leftnav"></router-outlet>
</div>
<div class="col-sm-10">
<router-outlet name="content"></router-outlet>
</div>
</div>
</div>
<app-footer class="site-footer"></app-footer>
So far, this module has routing like this
path: 'basic',
component: SplitviewsComponent,
data: {
containerType: 'container'
},
children: [
{
path: '',
component: LeftnavBasicComponent,
outlet: 'leftnav'
},
{
path: '',
component: Content1Component,
outlet: 'content'
}
]
},
So now if you went to /demo/splitviews/basic you'd see the splitviews component with the header, footer, and the 2 route outlets displaying LeftnavBasicComponent and Content1Component.
But now what I need to do is have the links in the LeftnavBasicComponent load different content components (e.g. Content2Component) inside the router-outlet "content". And I'm not sure how to best configure those sub-routes.

You can use the LeftnavBasicComponent and Content1Component as placeholders and then the components you really want to show will be loaded inside them depending on a value you'll pass by url.
Your html will be like below
<app-header class="site-header"></app-header>
<div class="site-content"></div>
<div [ngClass]="containerType"
class="splitview-wrapper">
<div class="row">
<div class="col-sm-2"">
<app-leftnav></app-leftnav>
</div>
<div class="col-sm-10">
<app-content></app-content>
</div>
</div>
</div>
app-leftnav and app-content are respectively the selectors of LeftnavBasicComponent and Content1Component.
The routing module will simply look like below:
{
path: 'basic/:leftnavtype/:contenttype',
component: SplitviewsComponent,
data: {
containerType: 'container'
}
}
Now in the LeftnavBasicComponent typescript file we have to take the value of leftnavtype from the url and put it in a variable like below:
leftNavType: string;
ngOnInit() {
this.route.params.subscribe((params: Params) => {
this.leftNavType = params["leftnavtype"];
});
}
And finally in the LeftnavBasicComponent html file we show a specific component depending on the leftNavType value
<app-type-1-left-nav *ngIf="leftNavType==='type1'"></app-type-1-left-nav>
<app-type-2-left-nav *ngIf="leftNavType==='type2'"></app-type-2-left-nav>
The same will be done for the content placeholder.
After doing so, if you call /demo/splitviews/basic/type1/content3, the type1 component will be loaded in the left nav placeholder and the content3 component will be loaded in the content placeholder, and you can then generate the link you want in the navigation part to load a specific component in the content part.
It may not be the perfect solution, but it works in your case.
And if there is only few cases, I suggest simply creating a route for each one, both solutions work depending on your needs.
Happy to clarify more if needed!

Related

Vue router nested routes renders with parent

So Iv'e tried to nest my routes unsuccessfully using Vue router.
{
path: '/admin',
name: 'Admin', component: () => import('pages/Admin'),
children:[
{ path: 'stock', name: 'Stock', component: ()=> import('pages/Stock')},
]},
It did not work so I found out that I need to put inside the parent component.
Now it works but if I load the page /admin/stock it renders the two componets. one on top of the others.
Why the parent component (/admin page) is still displayed?
Btw when I did the same thing without nesting the routes it worked perfectly fine and the components rendered seperatly(the snippet below).
{
path: '/admin',
name: 'Admin', component: () => import('pages/Admin'),
children:[
//no nested route
]},
{ path: 'admin/stock', name: 'Stock', component: ()=> import('../pages/Stock')},
Thanks for the help
You should include in "Admin" component a router-view tag. Admin component will work as a "layout" and it will render the children corresponding to the current route.
In example
Admin Component:
<template>
<div>
<div>
Content present in all childrens
</div>
<router-view>
<div>"Admin" page content</div>
</router-view>
</div>
</template>
Stock component:
<template>
<div>
"Stock" content
</div>
</template>
When you go to /admin
It will render:
<div>
<div>
Content present in all childrens
</div>
<div>"Admin" page content</div>
</div>
When you visit /admin/stock
It will render:
<div>
<div>
Content present in all childrens
</div>
<div>"Stock" content</div>
</div>
Here you have a better example
https://router.vuejs.org/guide/essentials/nested-routes.html
If you don't need reuse "Admin" component layout, you could use routes as you mentioned in the second case, without nesting them

Render nested routes as individual pages in VueJS

I'm using VueJS's own router component. In my admin interface, there is one page which shows an overview list and another one with specific options for one single entry.
function configRoutes() {
return [
{
path: '/',
redirect: '/default',
name: 'Home',
component: TheContainer,
children: [
{
path: 'admin/viewerRoles',
name: 'List',
component: AdminViewerRoles,
children: [
{
path: ':id-:name',
name: 'Settings',
component: AdminViewerRoleSettings
}
]
}
]
}
]
}
With that approach, I can place a <router-view /> tag in my AdminViewerRoles component. This will render the details page as viewport. What I wonder is, if it is possible to render either of the views without giving up the syntactically correct, nested navigation approach.
My idea would be to place the <router-view /> tag and the normal page content in two different div elements and render them conditionally with v-if. But is that really the best approach?
This would be my idea (untested):
<template>
<div v-if="$route.params.id">
<router-view />
</div>
<div v-else>
<table>...</table>
</div>
</template>

Sending props from different routes to the same component using Vue JS

I'm building a menu app using Vue JS. I was told that only have to use 1 component if the styling stays the same. So that means i have to use dynamic data. each menu/submenu has 3 to 4 menu links. I was looking for a solution to send variables with data to a component and came up with 'props'. But i couldn't find a way to send props from different routes to the same component and check which route you're on to know which props to load into the html.
I already tried to load props into a template, and that works fine. But sending and replacing prop values in the same part of html is something i haven't figured out yet.
{ path: '/list', component: List, props: { url: 'www.google.com' } }
<template>
<div class="container">
<h1>Welkom</h1>
<div class="row">
<div class="col-md-6">
<router-link to='/weed'>Wiet</router-link>
</div>
<div class="col-md-6">
<router-link to='/stuff'>Stuff</router-link>
</div>
<div class="col-md-6">
<router-link to='/joint'>Joint</router-link>
</div>
<div class="col-md-6">
<router-link to='/edibles'>Edibles</router-link>
</div>
</div>
</div>
</template>
the <router-link> should dynamic depending on which route you are, so it can load in different menu items.
I want a menu that loads in different route links depending on which route you are.
I think you should use Programmatic Navigation and query params like
router.push({ path: 'register', query: { plan: 'private' } })
so for your application use
<div class="col-md-6"
#click="$router.push({ path: '/edibles',
query: { url: 'www.google.com', other: 'etc' }})"
>Edibles</div>
you can access these query params in the navigated component using $route.params.url in a template and this.$route.params.url in functions and computed and all other properties of vue component instance.
also check https://router.vuejs.org/guide/essentials/navigation.html for details
Edit as per comment
I think you should still use Programmatic Navigation with
router.push({ name: 'user', params: { userId } })
the params provided can be used as props to the component as shown below
const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true }
]
})
just remember to set props: true in routes definition!
You can use params from your route as props in your component and use a watcher to react to route changes. Either have a state system (vuex) with which you can access specific data regarding the params or just plainly use the params.
Use: router.push({ path: '/user/${userId}' })
then
watch: {
$route(to, from) {
// react somehow
}
}
and/or
template: '<div>User {{ $route.params.id }}</div>'

How to display only specific page via router-view?

can only a specific page be viewed via router-view?
App.vue
<div id="app">
<div class="out-page" v-if="$route.path === '/login'">
<router-view name="login"></router-view>
</div>
<div class="register-page" v-if="$route.path === '/register'">
<div class="register-wrapper">
<router-view name="register"></router-view>
</div>
</div>
<div class="in-page" v-if="$route.path === '/home'">
<div class="home-container>
<router-view name="home"></router-view>
</div>
</div>
</div>
router.js
export default new Router({
mode: "history",
routes: [
{
path: "/login",
name: "login",
component: () =>
import(/* webpackChunkName: "Login" */ "./pages/login.vue")
},
{
path: "/register",
name: "register",
component: () =>
import(/* webpackChunkName: "Register" */ "./pages/register.vue")
},
{
path: "/home",
name: "home",
component: () =>
import(/* webpackChunkName: "Home" */ "./pages/home.vue")
}
]
});
I need the router-view to enter only content from one particular page, not all of them. The name attribute does not work.
Is it possible to do this?
It's not entirely clear what you are trying to do, but normally, if you have only a single view on the page, the app structure would look more like this:
<div id="app">
<div class="shared-outer-class">
<router-view/>
</div>
</div>
The per view customization would be handled in the individual components themselves, or by some shared outer component if needed.
If you are intending to use multiple views on same page, then you might used named views. But that is not what your example seems to be trying to do.

Ionic 4 and using material tabs router outlet

I am wanting to use Material Tab's (https://material.angular.io/components/tabs/api#MatTabLink) within my Ionic 4 project, now, the requirements are that I need to house multiple views in a tab and the first thought was that I can use a new ion-router-outlet or router-outlet within my parent component.
Bare in mind that I do already have one router outlet for the main app.
I am lazy loading the main chat routes in my app-routing.module.ts, this page is responsible for loading the tabs.
{ path: 'chat', loadChildren: './chat/chat.module#ChatPageModule', canActivate: [ AuthGuard ]}
Now, in my chat.module.ts I have the following routes:
{ path: '', component: ChatPage },
{ path: 'active', component: ActivePage },
{ path: 'messages', component: MessagesPage },
{ path: 'teams', component: TeamsPage }
ChatPage component is my parent tab view page. The others I am wanting to be in a tab.
The HTML for displaying these tabs is in chat.page.html and looks like this:
<nav mat-tab-nav-bar>
<a mat-tab-link
*ngFor="let link of routeLinks"
[routerLink]="link.path"
routerLinkActive #rla="routerLinkActive"
[active]="rla.isActive">
{{ link.label }}
</a>
</nav>
<router-outlet></router-outlet>
I have also tried <ion-router-outlet></ion-router-outlet> but this throws up more issues.
The main issue here is that the routes look as though they are loading up in the main router outlet rather than the child one, I have tried adding the name attribute to the mark up but my IDE states that it's not valid and doesn't seem to work.
Ok, I have figured it out, and I am going to look stupid for not trying this before but the issue was that in order to use this child router-outlet the routes I wanted in tabs need to child routes.
{ path: '', component: ChatPage, children: [
{ path: 'active', component: ActivePage },
{ path: 'messages', component: MessagesPage },
{ path: 'teams', component: TeamsPage }
] },

Categories