Angular Material Version: #angular/material#14.0.2
I am building a web application using the Angular framework for the first time.
The app-routing-module lazy loads a dashboard module that declares the desired components and imports the required modules. The dashboard module imports a dashboard routing module which holds the routes with the WrapperComponent as the parent and the side nav content as the children, split up into different components.
dashboard-routing.module.ts
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { AboutComponent } from './components/about/about.component';
import { DashboardComponent } from './components/dashboard/dashboard.component';
import { LoginComponent } from './components/login/login.component';
import { WrapperComponent } from './components/wrapper/wrapper.component';
const routes: Routes = [
{
path: '',
component: WrapperComponent,
children: [
{
path: 'dashboard', // --> localhost:4200/dashboard
component: DashboardComponent,
},
{
path: 'login', // --> localhost:4200/login
component: LoginComponent,
},
{
path: 'about', // --> localhost:4200/about
component: AboutComponent,
}
]
},
{
path: '**',
redirectTo: '/dashboard',
pathMatch: 'full'
}
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DashboardRoutingModule { }
wrapper.component.html
<mat-sidenav-container>
<mat-sidenav #sideNav mode="side" opened="opened">
<app-side-nav>
</app-side-nav>
</mat-sidenav>
<mat-sidenav-content>
<router-outlet></router-outlet>
</mat-sidenav-content>
</mat-sidenav-container>
The app-side-nav component consists of the router links.
<div class="sidenav">
<div class="logo">
<a (click)="toggleMenuState()" class="simple-text logo-mini">
<div class="logo-img">
<img src="./assets/images/sample_logo.png" alt="logo">
</div>
</a>
</div>
<ul class="nav">
<li class="active nav-list-item"><a routerLink="/default-route"><i class="fa fa-dashboard fa-nav-icon"><span class="nav-item-text">Dashboard</span></i></a></li>
<li class="nav-list-item"><a routerLink="/some-route"><i class="fa fa-group fa-nav-icon"><span class="nav-item-text">Groups</span></i></a></li>
<li class="nav-list-item"><a routerLink="/some-route"><i class="fa fa-line-chart fa-nav-icon"><span class="nav-item-text">Charts</span></i></a></li>
<li class="nav-list-item"><a routerLink="/some-route"><i class="fa fa-book fa-nav-icon"><span class="nav-item-text">Portfolio</span></i></a></li>
<li class="nav-list-item"><a routerLink="/login"><i class="fa fa-user fa-nav-icon"><span class="nav-item-text">Login</span></i></a></li>
<li class="nav-list-item"><a routerLink="/some-route"><i class="fa fa-gear fa-nav-icon"><span class="nav-item-text">Settings</span></i></a></li>
</ul>
This seems to work fine because I can see the relevant content being loaded in the DOM depending on the button clicked. But for some reason, the content is not visible.
Here is a screenshot of the dashboard component loaded. For some reason, it is loading with a margin of 1920px but even when removed the content is still not visible.
The structure seems to work yet there is something not quite right otherwise the content would show. Would appreciate any thoughts, suggestions or further questions.
I think your proble is material think that your app-side-nav or mat-sidenav have a full screen width, on the screenshot as I can see, content have a 1920px margin-left, this means that your view out of the bound of screen.
There is my example with correct margin, pay attention to your nav component:
Stackblitz example
Hope this helps.
After checking the rendered template it seems that your code lacks the routing precision.
Your app-routing.module.ts says that for path "" it should use DashboardModule. In the module you say that for path "" it should render a WrapperComponent. And after this point it has no default route.
So, basically what happens is that your wrapper component is rendered, however none of its children matches the route. To fix it, you have two options:
provide handler for "" route in the wrappers children routes
add a redirect to one of the routes using a wildcard route as I did in the Stackblitz fork of your GitHub project.
Stackblitz fork
That is to fix that router outlet does not render anything.
Another problem is <mat-sidenav #sideNav mode="side" opened="opened">, as you are assigning a string to the boolean flag, which means that it will be always truthy and won't display what's underneath.
In result removing opened="opened" and adding a redirection to the dashboard page we can see the "dashboard works!"
P.S. Looking at the examples in the docs it doesn't look to be designed to work the way you want it to. Rather show or hide behavior. Not expand.
P.S.S. You could try using autoresize and toggle width manually for the ever open sidenav as suggested here
Related
I dynamically created sidebar navigation list using router-link.
<template>
<div class="sidebarListItem bg-light">
<router-link
v-for="route in $router.options.routes"
:key="route.path"
:to="route.path"
class="list-group-item list-group-item-action bg-light">
{{route.title}}
</router-link>
</div>
</template>
<script>
export default {
name: "PageSidebarList",
computed: {
routes(){
return this.$router.options.routes
}
},
}
</script>
Each router-link is one map.
But then, I need to use <router-link> in some other place in my app, so I need to register new view (map) in router.js. The problem is I don't want this one view to be in sidebar list and it is automatically because of my code. I tried to separate routes in different files(one that I need for list and the rest of the views) and then importem them in router.js. but still it does't work. Or I don't know how to call them separatelly. I am new to vue and vue-router so please help. Is it possible to do what I want?
It's possible to add custom meta data to each route:
{
path: '/foo',
component: Foo,
meta: { hideInNav: true }
}
And then you can use a v-if on the router-link v-if="!route.meta.hideInNav"
Sorry to revive a question. Im using Angular 7 and Im trying to use Router Link.
This is my app-routing-module
const routes: Routes = [
{ path: 'locations' , component : LocationManagerComponent },
{ path: 'locations/create' , component : CreateEditLocationComponent },
{ path: 'locations/create/:id', component : CreateEditLocationComponent },
{ path: '404' , component : PageNotFoundComponent},
{ path: '**' , redirectTo: '/404'}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
This is router link:
<a [routerLink] = "['/locations']" routerLinkActive="active"> test link </a>
When I click on link, nothing happens. The URL on browser changed but component is not loaded.
If I press F5, component is loaded and from that point on, routers link works.
I've tryed a lot of stackoverflow solution like writing link in any sort of variant like
<a routerLink="/locations" ...
<a [routerLink]= ['/locations'] ...
<a [routerLink]= "['/locations']" ...
With or without LinkAttive attribute. Putting
<base href="/">
in index.html etc....
Following this topic: TOPIC I've tried to include Router in my Layout component:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-layout',
templateUrl: './layout.component.html',
styleUrls: ['./layout.component.css']
})
export class LayoutComponent implements OnInit {
constructor(
private route : ActivatedRoute
) { }
[...]
but nothing changes.
The strange part is that after an F5, all routes works, even route to component not yet loaded.
In this topic TOPIC 2 the user resolved removing css class. I've tried to put my link in a completely cleaned component HTML and it not working (but still works after a refresh).
<p>
dashboard works!
<a routerLink = '/locations' routerLinkActive="active"> test link </a>
</p>
UPDATE: This is layout.component where route tag is.
I can't figure out how to have a Sidenav without having route-outlet inside it.
<mat-sidenav-container fullscreen>
<mat-sidenav #sidenav mode="over">
<div class="profile_container">
<span> User Name </span>
</div>
<mat-nav-list>
<mat-list-item><a [routerLink]="['/locations']" routerLinkActive="active"> Locations
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content>
<app-header (toggleSidenav)="sidenav.toggle()"></app-header>
<div style="padding: 20px 10px 10px 20px;">
<router-outlet></router-outlet>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
Note: this answer is based on the previous version of your question, before you added the code of layout.component.html. So, instead of layout component, I am using the simplified dashboard component.
The below is working for me in Angular 8.1.
app.component.html
<app-dashboard></app-dashboard>
means that the DashboardComponent is contained within (is the child of) the AppComponent.
No change to the default app.component.ts
dashboard.component.html
<p>
dashboard works!
<a routerLink = '/locations' routerLinkActive="active">
Locations test link </a>
</p>
<p><a routerLink = '/locations/create' routerLinkActive="active">
Locations/create </a></p>
<p><a routerLink = '/locations/create/:id' routerLinkActive="active">
Locations/create/:id </a></p>
<p>router-outlet is below:</p>
<router-outlet></router-outlet>
All the links are working with click and with manually entering the url (eg: http://localhost:4200/locations/create/:id) in the browser and with reload (F5).
New Components
Generated using the ng generate component command:
Dashboard
LocationManager
CreateEditLocation
PageNotFound
app-routing-module.ts
The same as your file, but also added import statements for the newly generated components.
I figured what cause the problem but I can't unserstand why and I was not able to reproduce in StackBlitz.
This was my app.component.html, the root of all app:
<main>
<!-- Showing All Site Pages -->
<span *ngIf='isLogged()'>
<app-layout style="height:100%"></app-layout>
</span>
<!-- Showing Login Page -->
<div *ngIf='!isLogged()'>
<router-outlet></router-outlet>
</div>
</main>
The App-Layout code is above.
THIS NOT WORKS!
I changed it with a simply:
<main>
<app-layout style="height:100%"></app-layout>
</main>
As you see from my question, Layout has its own router-outlet.
I think the problem is the two router-outlet tag. Maybe Angular is not able to understand thats they are mutually exclusive. Maybe when I was clicking on menu, for some reason, Angular was updating the "first" router-outlet encountered and only after a refresh (F5), when the isLogged was already triggered and the app-layout was loaded directly, Angular knows which router-outlet to use.
In the new Way all pages, even Login, has to be child of AppLayout so every Layout component that's exists only if logged, has to be manually hide with *ngIf='!isLogged()'
A little price to pay to have routes works.
I've been working on an e-commerce like page as the attached images, and now I'm trying to do the basically same thing using vue-router.
In the previous version (without vue-routing) I could navigate through different pages, for example from the Main page to Cart page, shown as the attached images, but when I tried to do the same with vue-routing I couldn't jump to the cart page. Besides just clicking the "Cart" tab, I also tried adding
/#/cart
at the end of the URL by directly typing it in, but that didn't work either.
At this moment I'm following a series of video lectures, so I'm referring to the sample code provided. So if it were caused by some typing errors, there would be some error messages like
"undefined XXX"
"cannnot find XXX"
etc
displayed on the console.
But there is no error message displayed on console, so it's hard to identify where to start to look for the cause of this bug.
I found another question about vue-routing on Stack Overflow, but the cause of the error for that particular case was that he / she was trying to directly reference HTML files in the route configuration, which I don't think has something to do with my problem, so I think I need to ask my own question.
The below are some parts of the code for this e-commerce like practice app.
main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router';
import ProductList from './ProductList.vue';
import Cart from './Cart.vue';
Vue.filter('currency', function(value){
let formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFranctionDigits: 0
});
return formatter.format(value);
});
export const eventBus = new Vue();
Vue.use(VueRouter);
const router = new VueRouter({
routes: [
{ path: '', component: ProductList },
{ path: '/cart', component: Cart}
],
mode: 'history'
});
new Vue({
el: '#app',
render: h => h(App),
router: router
})
App.vue (only template part)
<template>
<div class="container">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
E-commerce Inc.
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>Products</li>
<li>Cart</li>
</ul>
<div class="nav navbar-nav navbar-right">
<div class="stats">{{ cart.items.length }}
<template v-if="cart.items.length == 1">item</template><template v-else>items</template>in cart, totalling {{ cartTotal | currency }}
</div>
</div>
</div>
</div>
</nav>
<router-view :cart="cart"></router-view>
</div>
</template>
Can it be something wrong with the content of the code, or is it possible that I didn't install something vital for vue-routing? So far I have at least installed vue-router, and also enabled and registered it.
I am trying to build a layout using single-file components in Vue.js, with dynamic population and URLs using Vue-router. (I'm using the webpack template via vue-cli as well.)
It works as expected for my app.vue file-- containing the nav, sidebar, page head, and <router-view>-- and the <router-view> content appeared as expected when the correct <router-link> is clicked... until I tried to add subcomponents to the add-load component being called to the <router-view>. Now, nothing appears at all, despite not throwing any errors.
Admittedly, I am not basing my structure on any examples, as I couldn't really find any doing it the way I was hoping to. I wanted to use nested components by calling them like custom elements-- I think this makes the code much easier to read and maintain. I'm not entirely sure how to structure it otherwise, to be honest. Using multiple <router-view>s as siblings to each other seems counterintuitive to me.
I've tried a variety of combinations of how and where to import and call the components, and nothing has worked. The only way I can get any content to load is if I only call a single component for path: '/add-load'. Is it just impossible to use multiple components outside of your base app.vue? I find that hard to believe. Here's what I started with.
From my index.js:
import AddLoad from '#/components/AddLoad'
import AddLoad from '#/components/ProgressSteps'
import Stops from '#/components/Stops'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
components: {
Sidebar,
TopNav,
MobNav,
PageHead
}
},
{
path: '/add-load',
components: {
AddLoad,
ProgressSteps}
}
]
})
From my App.vue file (the multiple component behavior that I'd like to mimic is shown here):
<template>
<div id="app">
<div class="wrapper">
<Sidebar/>
<div class="container-fluid">
<TopNav/>
<MobNav/>
<div class="container-fluid">
<PageHead/>
<router-view></router-view>
</div>
</div>
</div>
</div>
</template>
<script>
import Sidebar from '#/components/Sidebar'
import TopNav from '#/components/TopNav'
import MobNav from '#/components/MobNav'
import PageHead from '#/components/PageHead'
export default {
name: 'App',
components: {
Sidebar,
TopNav,
MobNav,
PageHead
}
}
</script>
From my AddLoad.vue file:
<template>
<div class="add-load">
<div class="content-container container-slim">
<progress-steps/>
<router-link to="#stops">Stops</router-link>
<router-view></router-view>
</div>
</div>
</template>
<script>
import ProgressSteps from '#/components/ProgressSteps'
export default {
name: 'AddLoad',
component: ProgressSteps
}
</script>
Here is a link to a codesandbox, so you can see the full functionality. https://codesandbox.io/s/7k520xk0yq
I've got this working, but I'm sure there's a better way to do this in Angular. Essentially I've the following:
Assume nested, inflected paths, e.g. /logos and /logo/:id
I have the following markup, which works:
<li class="nav-item">
<a class="nav-link" routerLinkActive="active" links="logo" routerLink="logos">
Logos
<span routerLink="logo" hidden></span>
</a>
</li>
This will properly cause the tab to activate on /logo/:id, however that span in there feels really hacky and incorrect. If the paths are not inflected, e.g. /logo and /logo/:id or /logos and /logos/:id it works fine. Do I just add another router link? Should I add some other directive? Do I need to go custom?
Thanks!
As your router is setup like this; (assuming logos is after the root, i.e. /logos)
{
path: 'logos',
component: LogosComponent
},
{
path: 'logo/:id',
component: LogoComponent,
}
There's only two types of links you need to have:
Link to all the logos:
<a routerLink='/logos'>All Logos</a>
Link to a single logo:
<a routerLink='/logo/specific-logo'>Specific Logo</a> , where "specific-logo" is the ID of the logo you want to go to.
If you want to have /logos seem active while you are in the /logo/specific-logo directory, I don't think it's possible (except for the workaround you found). However, you can simulate it using a computed value, i.e.:
<a class="nav-link" [class.active]="logoRouteActive" links="logo" routerLink="logos">
Logos
</a>
import { Router } from '#angular/router';
// ...
constructor(private router: Router) { /** ... */ }
get logoRouteActive(): boolean {
return this.router.isActive('/logo', false) || this.router.isActive('/logos', false);
}