Angular routing confusion/strange behavior - javascript

I have a base route with three sibling routes. The parent route routes to my task-list.component.ts which contains a navbar and router outlet.
I would like to have a route param on the base route where I can add an optional token
so when I navigate to http://localhost:4200 token should be undefined.
when I navigate to http://localhost:4200/123 token should be 123 in the activated route params
I have the below route config but i'm encountering confusing/strange behaviour.
When I navigate to http://localhost:4200 I get to my base taskList.component as expected.
When I try navigate to http://localhost:4200/123 I get a 404 not found? The expected bahaviour is that this should have navigated to taskList.component and added 123 to the activated route params...
even more strange when I click the deleted link in my navbar it navigates to the parent component app.component again only then I get "deleted" as the value in the activated route params...
Even more strange: when I navigate to http://localhost:4200 using my browser it doesn't set deleted as token instead I get a 404 not found again...
Any idea how I can achieve the above/what my issue might be?
my route module code:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
import { TaskListComponent } from './task/task-list/task-list.component';
import { CompletedTasksComponent } from './task/completed-tasks/completed-tasks.component';
import { DeletedTasksComponent } from './task/deleted-tasks/deleted-tasks.component';
const routes: Routes = [
{ path: '', component: TaskListComponent, pathMatch: 'full' },
{ path: 'completed', component: CompletedTasksComponent },
{ path: 'deleted', component: DeletedTasksComponent },
{ path: ':token', component: TaskListComponent },
{ path: ':token/completed', component: CompletedTasksComponent },
{ path: ':token/deleted', component: DeletedTasksComponent }
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.component.html:
<nav mat-tab-nav-bar>
<a mat-tab-link
*ngFor="let link of links"
[routerLink]="navigate(link)"
(click)="activeLink = link"
[active]="activeLink == link">{{link}}</a>
</nav>
<router-outlet></router-outlet>
app.component.ts navigate method
navigate(link) {
switch(link) {
case 'Task List':
return `${this.token}`;
case 'Completed Tasks':
return `${this.token}/completed`;
case 'Deleted Tasks':
return `${this.token}/deleted`;
}
}

Old answer: You have some issues in your routes. you can fix it like :
RouterModule.forRoot([
{ path: "", component: TaskListComponent, pathMatch: "full" },
{ path: "deleted", component: DeletedTasksComponent },
{ path: ":id", component: TaskListComponent },
{ path: ":id/completed", component: CompletedTasksComponent },
{ path: ":id/deleted", component: DeletedTasksComponent }
])
Run It On Stackblitz
Update :
based on your edit and comments, now in app navigation works but you get 404 when you refresh the page (even in development environment). so try this: https://stackoverflow.com/a/35285068/4718434 . (Also on production, you should configure your server to return angular html file on every path.)

Related

Angular SSR app fail to render homepage from url while server is running

I have an Angular SSR app that is not able to render the homepage via localhost:4000 while the backend node server is running.
So if I go to localhost:4000 it will start loading but never display anything nor finished loading. However, if I go to another page like 404 where I have a button to take me to the home page it does load it. Additionally, if I turn off the backend server it does load the homepage.
The app routes are handled like this:
//app-routing.module.ts
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { GuardDashboardGuard } from './guard-dashboard.guard';
import { KYCGuard } from './guard-kyc.guard';
// More imports for other paths
const routes: Routes = [
{
path: 'profile-update',
canActivate: [GuardDashboardGuard, KYCGuard],
loadChildren: () =>
import('./pages/profile-update/profile-update.module').then((m) => m.ProfileUpdatePageModule),
},
// More paths with the same structure
{
path: '',
loadChildren: () => import('./pages/home/home.module').then((m) => m.HomePageModule),
},
{
path: 'faqs',
loadChildren: () => import('./pages/faq/faq.module').then((m) => m.FaqPageModule),
},
{
path: '',
redirectTo: '/',
pathMatch: 'full',
},
{ path: '**', redirectTo: '404' },
];
#NgModule({
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled',
scrollOffset: [0, 0],
anchorScrolling: 'enabled',
relativeLinkResolution: 'legacy',
initialNavigation: 'enabledBlocking',
}),
],
exports: [RouterModule],
})
export class AppRoutingModule { }
I have tried fully deleting path: '', and the app redirected localhost:4000 to profile-update. Even if i delete profile-update I am still redirected to a Update Profile page.
Home page directory tree looks like:
.
├── home-routing.module.ts
├── home.module.ts
├── home.page.html
└── home.page.ts
// home-routing.module.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { HomePage } from './home.page';
const routes: Routes = [
{
path: '',
component: HomePage,
},
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class HomePageRoutingModule {}
I am not sure what the cause of this error is or what code is relevant so I don't know what other code should be included in my question.
I also get a network error of crbug/1173575, non-JS module files deprecated.
and have found this Crbug/1173575, non-JS module files deprecated. chromewebdata/(index)꞉5305:9:5551 which was not very helpful to solve thebug.

How can I set a default route in Angular?

I'm having problems developing a route as default... if you put sitename.com ... it assumes the default Login route, getting sitename.com/login, so far so good....
My problem is that if I go to the page through a sitename.com/home shortcut... I don't see any page, as if I couldn't find the path... I wanted to put this shortcut on the default page. .. Login.
To do this do I have to configure the routes or do I have to do something else?
Can anyone help me?
app.module.ts
import { RouterModule, Routes } from '#angular/router';
imports: [
RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' }),
],
const routes: Routes = [
{ path: '', redirectTo: 'login', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
];
You can try
RouterModule.forRoot(routes, {useHash: true})
and Login page will be accessed by direct URL as sitename.com/#/login

VueJs Router: App.vue Component shows up on every page

I'm working with currently with the Vue Router, but when I write something in App.vue it shows up on every page, why?
The app.vue will always render since it's the main component. To display a content specific to the page, you should use <router-view />. It will render the component you define on your route file. Here is the example
import { createRouter, createWebHistory } from 'vue-router'
import Login from '../views/Auth/Login.vue'
import Register from '../views/Auth/Register.vue'
import LandingPage from '../views/LandingPage.vue'
const routes = [
{
path: '/',
name: 'LandingPage',
component: LandingPage
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/register',
name: 'Register',
component: Register
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router

Angular uses wrong router-outlet

I have a problem with Angular routing. I have main app routing module and sub module with its own routing module and router-outlet but routes defined in this submodule are shown using root router outlet and not the child one.
My folder structure:
My code listings
app-routing.module.ts
const routes: Routes = [
{ path: '', component: HomeComponent, pathMatch: 'full' }
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.component.html
<router-outlet></router-outlet>
home-routing.module.ts
const routes: Routes = [
{ path: '', component: LandingPageComponent},
{ path: 'register', component: RegisterComponent },
{ path: 'login', component: LoginComponent }
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class HomeRoutingModule { }
home.component.html
...
<div class="inner cover">
<router-outlet></router-outlet>
</div>
...
That's what I get when I use empty path - it opens home component properly.
But when i enter /register i get plain html from login.component.html without template in home.component.html file
EDIT
I added name to child outlet
<router-outlet name="home"></router-outlet>
Changed route names to:
const routes: Routes = [
{ path: '', component: LandingPageComponent, outlet: 'home'},
{ path: 'register', component: RegisterComponent, outlet: 'home' },
{ path: 'login', component: LoginComponent, outlet: 'home' }
];
Now I got that error:
EDIT 2
I try to access those routes in 2 ways:
A link(which may be incorrect):
<a routerLink="/login">Log In</a></li>
Or typing manually:
localhost:4200/login
In Angular 2, router outlets can be named:
<router-outlet>
<router-outlet name="children"></router-outlet>
</router-outlet>
App:
const routes: Routes = [
{ path: '', component: HomeComponent, pathMatch: 'full' }
];
Home:
const routes: Routes = [
{ path: '', component: LandingPageComponent, outlet: 'children'},
{ path: 'register', component: RegisterComponent, outlet: 'children' },
{ path: 'login', component: LoginComponent, outlet: 'children' }
];
You can even define child routes:
const routes: Routes = [
{ path: '',
component: HomeComponent,
pathMatch: 'full', children: [
{ path: '', component: LandingPageComponent, outlet: 'children'},
{ path: 'register', component: RegisterComponent, outlet: 'children' },
{ path: 'login', component: LoginComponent, outlet: 'children' }
]
}
];
http://onehungrymind.com/named-router-outlets-in-angular-2/
If you want those 3 components to be rendered inside of the HomeComponent in a named outlet, then you need to define the following routes:
const routes: Routes = [
{ path: '',
component: HomeComponent,
pathMatch: 'full'
},
{ path: 'landing', component: LandingPageComponent, outlet: 'children'},
{ path: 'register', component: RegisterComponent, outlet: 'children' },
{ path: 'login', component: LoginComponent, outlet: 'children' }
];
And inside of app.component.html add the named router outlet
....//html template
<router-outlet name="children"></router-outlet>
....//html template
EDIT 1:
To navigate to the named outlets you need to use the following routed links:
//inside of home.component.html
<a [routerLink]="[{ outlets: { children: ['login'] } }]">Take me to login!</a>
The generated link will look like:
root/(children:login)
More info in the following link to the docs
EDIT 2:
I changed the original routes and the component template where the named outlet is added. Why?
it is not possible, as far as I know, to have a named outlet with an empty path (''). The empty path tells angular that the named outlet is empty (no component is currently rendered in it).
I believe your problem has to do with declarations. I can not know for certain since you didn't show the code in your app.module.ts and home.module.ts file and have not tested this fully myself.
A component needs to be declared inside the module connected to the template with the desired routing outlet. In your case the login component would need to be added to "declarations" in your home.module.ts file and removed from "declarations" in the app.module.ts file.
Angular does not seem allow you to reuse the same component in multiple routing-outlets unless they are in the same template, since it would cause an error stating "x component declared in multiple modules".

Angular 2 Role based navigation on same path

I've a small question regarding Angular 2 router using version 3.0.0-rc.1 I want to navigate to different home component based on user role such as AdminComponent or UserComponent. Can anyone please help in modifying below routes so that I can achieve the desired functionality?
{path: 'login', component: LoginComponent}, // <--- This redirects to '/' in case user is logged in
{
path: '',
component: HomeComponent,
canActivate: [AuthGuardService], // <--- Check if user is logged in, else redirect to login
children: [
{
path: '',
component: AdminComponent // <--- Want to navigate here if user role is 'admin'
},
{
path: '',
component: UserComponent // <--- Want to navigate here if user role is 'user'
}
]
}
AuthGuardService.ts
import {Injectable} from "#angular/core";
import {CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot} from "#angular/router";
import {AuthService} from "./auth.service";
#Injectable()
export class AuthGuardService implements CanActivate {
constructor(private authService: AuthService, private router: Router) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (this.authService.isLoggedIn()) {
return true;
}
// Store the attempted URL for redirecting
this.authService.redirectUrl = state.url;
// Navigate to the login page with extras
this.router.navigate(['/login']);
return false;
}
}
AuthService.ts
import {Injectable} from "#angular/core";
#Injectable()
export class AuthService {
redirectUrl: string;
logout() {
localStorage.clear();
}
isLoggedIn() {
return localStorage.getItem('token') !== null;
}
isAdmin() {
return localStorage.getItem('role') === 'admin';
}
}
Thanks.
You can achieve it by below way.
{path: 'login', component: LoginComponent}, // <--- This redirects to '/' in case user is logged in
{
path: '',
component: HomeComponent,
canActivate: [AuthGuardService],
}
this is your home component html(home.component.html)
<app-admin *ngIf="user_role==='admin'"></app-admin>
<app-user *ngIf="user_role==='user'"></app-user>
make sure you are assigning user_role in your typescript file of home component
this is your admin component html(admin.component.html)
<div>
this is admin component
</div>
this is your user component html(user.component.html)
<div>
this is user component
</div>
Hope, This will help you.
The problem is that you can't have two routes with the same path. The easiest change you can make is to change the path to something like this:
{
path: 'admin',
component: AdminComponent
},
{
path: 'user',
component: UserComponent
}
This is probably the best option because since you want your components to be different based on the user role. You might also want other components to be different and you can do that easily by adding children to the admin or the user routes.
In your AuthGuard you still only return true, but you make two other guards for the admin and user routes. Which check if the user is or isn't the admin.
And you redirect to the correct route by checking the user role once he loges in and then in the component you do router.navigate(['/admin']) or router.navigate(['/user'])

Categories