Angular: 7.2.14 - Yet Another Router Link Not Working Topic - javascript

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.

Related

Angular Material mat-sidenav-content not showing

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

Vuejs: shared components used on multiple pages disappeared

right now, I'm writing a single-page-application in vue.js using vue-router. Pages like the homepage, sign-in page etc. all share a navigation and footer component. On a few pages however, I need the entire screen so that the navigation and footer shall not be displayed.
Hence, I decided to nest components and include the navigation and footer component when necessary. My problems now is, that the navigation and footer template disappeared on all pages.
Edit: A more complete demo can be found in this Github repository.
Here's a simplified version of the files I'm using:
index.html:
<div id="app">
<router-view></routerview>
</div>
router.js:
import Homepage from './homepage.vue';
import SignIn from './signin.vue';
const router = new VueRouter({
routes: [
{path: '/', component: Homepage},
{path: '/signin', component: SignIn},
]
})
homepage.vue and signin.vue components:
<template>
<navigation></navigation>
// some page-specific content
<footer-vue></footer-vue>
</template>
<script>
import Navigation from './navigation.vue';
import Footer from './footer.vue';
export default {
components: {
'navigation': Navigation,
'footer-vue': Footer,
},
}
</script>
A component without navigation and footer:
<template>
// some page-specific content
</template>
Is it even possible to nest components this way? I hope someone is able to point me into the right direction.
Both homepage.vue and signin.vue have invalid templates. e.g.
<template>
<navigation></navigation>
<h1>The homepage</h1>
<footer-vue></footer-vue>
</template>
This is not allowed as it has 3 root nodes. See https://v2.vuejs.org/v2/guide/components.html#A-Single-Root-Element
You need to wrap it to get it to work:
<template>
<div>
<navigation></navigation>
<h1>The homepage</h1>
<footer-vue></footer-vue>
</div>
</template>
Note that this limitation does not apply to functional components and is also expected to be lifted for all components in Vue 3.
Much more worrying is that you're not seeing any errors messages for this. You really need to look into that as it suggests there's something very much amiss with your development setup.
An example of the error message you should be seeing:
new Vue({
el: '#app',
template: '<div></div><div></div>'
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
</div>

Routing displays content of previous page too

I am building a web-page which starts with a simple login box which contains username,password with input boxes and two buttons with name login and register.
After clicking on the login button my page should route to another component which contains a navigation bar. It does route, no problem there. But the login box doesn't disappears after routing.
So after routing, navigation bar appears but the login box is still there.
APP.COMPONENT.HTML
<div class="background-image">
<router-outlet></router-outlet>
<div class="content2">
<h2 >Login</h2>
<br>
<form>
<div class="form-group">
<label style="margin: 5px">Username</label>
<input type="text" />
</div>
<div class="form-group">
<label style="margin: 7.5px">Password</label>
<input type="password" />
</div>
<div class="form-group">
<button (click)="onclick()" [disabled]="loading" class="btn btn-
primary">Login</button>
Register
</div>
</form>
</div>
</div>
APP.COMPONENT.TS
import { Component } from '#angular/core';
import { Router } from '#angular/router';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'welfareUI';
constructor(private router: Router){
}
onclick()
{
this.router.navigateByUrl('/navbar');
}
}
#Yash Anand Whatever #Adrita Sharma has said that is correct. You create a new login component and keep login html markup in login.component.html. keep only <router-outlet></router-outlet> in app.component.html Now when you click on login button it will only display you navbar.
Note- Make sure by default you have configured your route to go to login page in app.module.
routes: [{path : '', component: LoginComponent}]
This is because you have placed login html in app.component.html. <router-outlet></router-outlet> replaces the template of the current route, except that all the html in this file is constant.
You can create a separate login component. By default navigate to login component. Donot keep login html in app.component.html
Create separate component for login. Insert the HTML code in login.html and place router outlet in app.html file.
you have create loginComponent and place your login code inside it and then use router path to show login component as default
{ path: '',redirectTo: '/heroes',pathMatch: 'full'},
can refer below link
https://angular.io/guide/router#the-default-route-to-heroes
Create login component and load it initially into the router outlet.
routes: [{path : '', component: LoginComponent}]
After cliking on login button call different route you want to navigate.
routes: [{path : '/abc', component: abcComponent}]
There may be also a scenario when you are forcibly loading some component just before after router-outlet tag as in my scenario.
<div class="container">
<app-header></app-header>
<app-Product></app-Product>
<router-outlet></router-outlet>
</div>
On line number 2, I have all my router links. The main cause was line number 3 which is a component I was loading forcibly.
So after removing third line, everything was working properly. so if you are using Router-Outlet then let it decide about Components and their loadings.

Using a component containing other components within a router-view in Vue.js

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

Vuejs template inheritance

How can I use template inheritance (Like what jade has, extends file.jade and then the blocks with the same name would be overwritten)?
I know that I can do everything with composition, but for components like footer and header which appear on every single page except one or two (e.g.login page) I must write them on every single component. In my app I have a two level navigation and it seems painful to repeat them on every one of those child components :(
I know that I can use jade and then inherit a jade file within my components, but it seems wrong because I would have some jade and some Vue files, is there any other way to do this?
// Component.vue
<template lang="jade">
extends ./StandardLayout
block content
router-view
</template>
// StandardLayout.Vue
<template lang="jade">
div
navbar
div.container
div.spacer
div.row
block content
<template>
What I've settled for, is a layouts folder filled with jade layouts and I use them to extend my components. I used vue-cli with webpack template.
In the most general case if you have to repeat the same HTML over and over, one option you could use is <partial>s.
<partial name="header"></partial>
<div>My content content</div>
<partial name="footer"></partial>
Where you declare partials as
Vue.partial('header', '<h3>This is the title: {{title}}</h3>')
Vue.partial('footer', '<footer>Mini footer</footer>')
However if you are building a Single Page Application the strategy you could follow is to simply have a header and a footer around your <router-view>, here is a jsfiddle that demonstrates how to do.
https://jsfiddle.net/gurghet/vdqutw2y/
<header><h1>
My title: {{title}}
</h1></header>
<p>
<a v-link="{ path: '/foo' }">Go to Foo</a>
<a v-link="{ path: '/bar' }">Go to Bar</a>
</p>
<router-view></router-view>
<footer>Such footer, many links, wow!</footer>
If you know Chinses, please look it
// Base Component
<template>
<div class="base-thing special-class">
<Button />
</div>
</template>
<script>
import Button from './ButtonClick'
export default {
components: { Button }
}
</script>
// Inheriting Component
<script>
import BaseComponent from './BaseComponent'
import Button from './OtherButton'
export default {
extends: BaseComponent
components: {
Button
}
}
</script>
The Button of Child Component will be replaced OtherButton. We can do something in the OtherButton

Categories

Resources