How can I get my service variable in routing file.
I made a UserService which has a variable user and I want to access that variable in my routing file.
Below is my approach which didn't work:
In routing file, I wrote:
const steps = userService.user.onboardingStatus; //shows error ---> *cannot find name userService*
const routes: Routes = [
{
path: 'welcome',
component: WelcomeComponent,
},
{
path: 'product-selection',
component: ProductSelectionComponent,
canActivate: [ClientRoutesGuard],
data: {
isStepAccessible: steps.['welcome'].status, //will return true or false
},
},
]
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class ClientRoutingModule {
constructor(public userService: UserService) {}
}
Thanks in advance!
If you want the user to be able to go to the 'product-selection' route only when steps['welcome'].status is true, you should create a guard for it. For example:
export class ProductSelectionGuard implements CanActivate {
constructor(private userService: UserService) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
return this.userService.user.steps['welcome'].status;
}
}
Then include your guard in the canActivate array for your route:
// ... other routes
{
path: 'product-selection',
component: ProductSelectionComponent,
canActivate: [ClientRoutesGuard, ProductSelectionGuard],
// data: {
// isStepAccessible: steps.['welcome'].status, //will return true or false
// },
},
Related
im starting to work with Angular, and im trying to create a simple route guard, to redirect user to login page, if my service return unauthorized.
To do that i created this route schema ->
const routes: Routes = [
{
path: '',
component: LoggedComponent,
children: [
{path: '', component: HomeComponent}
],
canActivate: [RouteGuard]
},
{
path: '',
component: AuthComponent,
children: [
{path: '', redirectTo: '/login', pathMatch: 'full'},
{path: 'login', component: LoginComponent},
{path: 'signin', component: SigninComponent}
]
},
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
And this is my guard service ->
PS: Im setting a default value false.
import {Subject, Observable} from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class RouteGuard implements CanActivate {
authorized: Subject<boolean> = new Subject();
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
this.setObservable(false)
return false;
}
getObservable(): Observable<boolean> {
console.log(`starts to observe`)
return this.authorized.asObservable();
}
setObservable(newState: boolean) {
console.log(`new observable state: ${newState}`)
this.authorized.next(newState)
}
}
Ok, since the value is returning false as default, I expect the route to be automatically redirected to the AuthComponent, because Auth is the second option at my routes[]. Right?
So...
At the AuthComponent i stated to observe the authorized status:
import {RouteGuard} from '#acn-collections-ws/shared';
#Component({
selector: 'acn-collections-ws-auth',
templateUrl: './auth.component.html',
styleUrls: ['./auth.component.scss']
})
export class AuthComponent implements OnInit {
constructor(private guard: RouteGuard, router: Router) {
console.log('im here');
this.guard.getObservable().subscribe(authorized => {
})
}
ngOnInit(): void {
}
}
But AuthComponent dosent load. it seems that when the canActivate parameter returns false, it does not go to the AuthComponent, it does not load anything. When the authorized (canActivate) returns true, it runs normally. Has anyone had a similar problem and can help me?
This is how I do it when authenticating using Firebase:
export class GuardGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router){}
async canActivate() {
const user = await this.authService.isLogged();
if(user){
return true;
}
else {
this.router.navigate(['login']);
return false;
}
}
}
If the user's logged return true so it loads the requested route if not redirects to the login route and return false.
And this is the routing:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { LoginComponent } from './modules/login/pages/login/login.component';
import { SignupComponent } from './modules/login/pages/signup/signup.component';
import { HeroComponent } from './shared/components/hero/hero.component';
import { NotFoundComponent } from './shared/components/not-found/not-found.component';
import { GuardGuard } from './shared/guards/guard.guard';
const routes: Routes = [
{ path: 'home', component: HeroComponent },
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'signup', component: SignupComponent },
{ path: 'login', component: LoginComponent },
{ path: 'tasks', loadChildren: ()=> import('./modules/task/task.module').then(m => m.TaskModule), canActivate: [GuardGuard] },
{ path: 'profile', loadChildren: ()=> import('./modules/user/user.module').then(m => m.UserModule), canActivate: [GuardGuard] },
{ path: '**', component: NotFoundComponent }
];
I'm building a Ionic app using Angular and calling an API to get some results. According to a particular property of the response object (such as "mode"="0" or mode="1" I need to change paths defined in app routing module, in particular to dynamically change the home page.
I'd like appcomponent (starting component) to call the API and to check the mode, then passing some routes according to that property.
E.g.:
I'd like to have something like:
if (mydata['mode']==="0") {
this.appRoutes = [
{
path: '',
redirectTo: 'firstPath',
pathMatch: 'full'
},
{
path: 'firstPath',
loadChildren: './firstpath.module#FistPathModule'
},
{
path: 'secondPath',
loadChildren: './secondpath.module#SecondPathModule'
}
]
} else if (my_data['mode']==="1") {
this.appRoutes = [
{
path: '',
redirectTo: 'secondPath',
pathMatch: 'full'
},
{
path: 'secondPath',
loadChildren: './secondpath.module#SecondPathModule'
},
]
}
Is there a way to do something like this inside the app-routing.module?
Hiding firstPath in the second case is possible as well?
This is not a correct way to make changes in app-routing file for such requirement.
You can use Guard to implement this.
In your child route file do like this:
{
path: '',
component: HomePage,
canActivate: [AuthGuard]
}
Auth Guard file:
import { Injectable } from '#angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot, CanActivate } from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
mode: number; **// You can save this mode variable into a common service and use it.**
constructor() { }
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): any {
if(this.mode == 1) {
return false;
}else {
return true;
}
});
}
}
I have the following routes in the application. the problem here is if I navigate to say getEmp-by-id or page-not-found and hit refresh, then application is landing on app-home,. But I want it to stay on the same page where refresh is hit.I am not implementing any RouteGuards, simple navigations. Is there a way I can acheive this.
const appRoutes: Routes = [
{path: '', component: HomeComponent, children: [
{path: 'app-home', component: AppHomeComponent, resolve: {ApphomeResolver : AppHomeResolver}},
{path: 'getEmp-by-id', component: EmpComponent},
{path: 'page-not-found', component: pageNotFoundComponent},]
},
{path: '**', redirectTo: 'page-not-found', pathMatch: 'full'}
];
export class EmpComponent implements OnInit {
constructor(private router: Router, private route: ActivatedRoute, private alertService: AlertService, private employeeService: EmployeeService) { }
ngOnInit() {}
onSubmit() {
this.employeeService.getEmployee(empId).subscribe(
(data) => {
var responseCode = JSON.parse(data).responseCode;
var responseMessage = JSON.parse(data).responseMessage
if (responseCode === 200) {
this.router.navigate(['../emp-details'], { relativeTo: this.route });
} else {
this.router.navigate(['../page-not-found'], { relativeTo: this.route });
}
}, error => {
this.router.navigate(['../page-not-found'], { relativeTo: this.route });
});
} else {
this.alertService.error("Error");
}
}
}
One way of handling page refreshes is to using hash routing. To implement this, write the following code in app.module.ts:
import { APP_BASE_HREF, LocationStrategy, HashLocationStrategy } from '#angular/common';
#NgModule({
......
providers: [
{ provide: APP_BASE_HREF, useValue: '', }
, { provide: LocationStrategy, useClass: HashLocationStrategy }
.....
]})
export class AppModule {
}
Please note that this will add # to your route.
I'm having trouble capturing the original navigating route using a guard in Angular 2.
My site consists of a core module protected by an authorization guard, and a login page that's unprotected.
The core module has it's own sub routes defined in it's own app routing file, and any undefined routes are redirected to the root path.
Here's my top level routing module.
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { AuthGuard } from './auth';
const routes: Routes = [
// Login module is public
{ path: 'login', loadChildren: 'app/auth/auth.module#AuthModule' },
// Core route protected by auth guard
{ path: '', loadChildren: 'app/core/core.module#CoreModule', canLoad: [AuthGuard] },
// otherwise redirect to home
{ path: '**', redirectTo: '' }
];
#NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
And here is the AuthGuard class.
import { Injectable } from '#angular/core';
import { Router, CanLoad, Route } from '#angular/router';
import { AuthService } from './auth.service';
#Injectable()
export class AuthGuard implements CanLoad {
constructor(
private authService: AuthService,
private router: Router
) {}
canLoad(route: Route): boolean {
this.authService.redirectUrl = `/${route.path}`;
console.log('path:' + route.path);
if (this.authService.isLoggedIn()) {
return true;
} else {
this.router.navigate(['/login']);
return false;
}
}
}
This is a pretty straightforward login/redirect scheme, however the route.path value is always empty, regardless of what URL I navigate to. I have a hunch that it has something to do with the { path: '**', redirectTo: '' } route but I'm not sure.
I don't want to use canActivate because I only want the main module loaded if the user is actually logged in.
What I expected was that if I navigate to /foobar then route.path would be set to foobar in the AuthGuard class but it is not. It is always empty, thus I am unable to do a correct redirect after the user logs in.
Try adding the pathMatch: 'full' like this:
{path: '**', redirectTo: '', pathMatch: 'full'}
or
import {CanActivate, RouterStateSnapshot, ActivatedRouteSnapshot} from "#angular/router";
import { Subscription, Observable } from "rxjs/Rx";
export class HomepageGuard implements CanActivate {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
console.log(`[homepage.guard.ts]-[canActivate()]`);
console.log(route);
console.log(state);
// are you allowed to continue
return true;
}
}
I have this code.
Route 'new' this child route for 'users'.
Route 'users' has resolver.
This work fine.
But after success create user.
I redirect to 'users', but new user not display in list, because
DataResolver not work after redirect from child route.
How Can i fix it?
//Roiting
export const ROUTES: Routes = [
{ path: 'dashboard',
component: Dashboard,
children: [
{ path: 'users',
component: Users,
resolve: {
users: DataResolver
},
children: [
{ path: 'new', component: NewUser }
]
},
]
}
];
//Resolver
#Injectable()
export class DataResolver implements Resolve<any> {
constructor(private userService: UserService) {}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
return this.userService.all(); // return users
}
}
//Component
export class NewUser {
errorMessage: string;
user: User;
constructor(public route: ActivatedRoute,
private userService: UserService,
private router: Router) {
this.user = new User();
}
onSubmit(): void {
this.userService
.createUser(this.user)
.subscribe(
user => {
this.router.navigate(['/dashboard', 'users']);
},
error => this.errorMessage = <any>error);
}
}
// USers component
export class Users implements OnInit {
users: User[];
constructor(public route: ActivatedRoute,
private router: Router) {
this.route.data.subscribe((data: any) => {
this.users = data.users;
});
}
}
Your 'Users' component should be like this, I assume you return User[] type from your web service;
export class Users {
users;
constructor(private _route: ActivatedRoute, ...){
_route.data.subscribe((wrapper: {res: any[] }) => {
this.users = <User[]>wrapper.res;
});
}
}
When your link is .../dashboard/user, it gets users via resolver and wrap it. I just call it as wrapper, you can give another name. Just know that after resolving, it wraps the response from your service.
Please let me know if you need more information.
Edit 1:
Here is how I use resolver, I hope it helps
//app.route
const appRoutes: Routes = [
{
path: '',
redirectTo: 'user',
pathMatch: 'full'
},
{
path: 'user',
loadChildren: '.../user.module#UserModule'
}
];
const rootRoutes: Routes = [
...appRoutes
];
export const appRouting = RouterModule.forRoot(rootRoutes, { useHash: true });
//user.route
const userRoutes: Routes = [
{
path: '',
component: UserComponent,
children: [
{
path: 'create',
component: UserCreateComponent
},
{
path: '',
component: UserListComponent,
resolve: {
res: UserResolver
}
}
]
}
];
export const userRouting = RouterModule.forChild(userRoutes);
//user.module
#NgModule({
imports: [
CommonModule,
ReactiveFormsModule,
userRouting,
FormsModule
],
declarations: [
UserComponent,
UserCreateComponent,
UserListComponent
],
providers: [
UserService,
UserResolver
]
})
export class UserModule { }
//user.resolver
export class UserResolver implements Resolve<any>{
constructor(private service: UserService) { }
public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
return this.service.get();//return all users
}
}