Angular 2 resolve for parent route - javascript

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
}
}

Related

access service variable in routing file

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
// },
},

how to use AuthGuard correctly

I have an angular application where I want to use authguard to protect some routes but for some reason it does not work. I first make a post request to my spring boot backend, if that gives me success I set a value to true and check that value in my canActivate methode. But it does not work, it does not even go into that method. I thought it is called automatically if I set it in my path in app-route.module. How can I use it correctly?
Authenticationservice with authguard together:
export class AuthenticationService {
constructor(
private http: HttpClient,
private router: Router,
) { }
authenticateUser(login: LoginModel){
return this.http.post(environment.rootUrl + 'authenticate', {
username: login.username,
password: login.password,
}).subscribe({
next: (data) => {
localStorage.setItem('token', data.toString())
}, error: (error) => {
this.isAuthenticated = false
}
})
}
isUserLoggedIn(){
return !!localStorage.getItem('token')
}
}
Authguard:
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(
private auth: AuthenticationService,
private router: Router
) {
}
canActivate(): Promise<boolean> {
return new Promise(resolve => {
if (this.auth.isUserLoggedIn()) {
resolve(true)
} else {
this.router.navigate(['authenticate'])
resolve(false)
}
})
}
}
App-module:
#NgModule({
declarations: [AppComponent, NxWelcomeComponent],
imports: [
BrowserModule,
BrowserAnimationsModule,
NbLayoutModule,
LoginComponentModule,
AppRoutingModule,
NbThemeModule.forRoot({ name: 'default' }),
NbLayoutModule,
NbEvaIconsModule,
],
providers: [AuthGuard],
bootstrap: [AppComponent],
})
export class AppModule {}
App-routing-module:
const routes: Routes = [
{path: 'dashboard' , component: DashboardComponent, canActivate: [AuthGuard]},
{path: 'authenticate', component: LoginComponent},
{path: '' , redirectTo: 'authenticate', pathMatch: 'full'}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [AuthGuard]
})
export class AppRoutingModule {
}
You need to route to the dashboard after you do the login:
The routes:
const routes: Routes = [
{
path: 'dashboard',
component: DashboardComponent,
canActivate: [AuthGuard],
},
{ path: '', redirectTo: 'authenticate', pathMatch: 'full' },
];
The Component:
export class AppComponent {
constructor(
private authService: AuthenticationService,
private router: Router
) {}
callServiceMethod(value: string) {
// This will need to wait for auth to finish before navigating in the actual app.
this.authService.authenticateUser(value);
if (this.authService.isAuthenticated) {
this.router.navigate(['dashboard']);
}
}
}
The Guard:
#Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(private auth: AuthenticationService, private router: Router) {}
canActivate(): Promise<boolean> {
return new Promise((resolve) => {
console.log('running auth guard!');
if (this.auth.isUserLoggedIn()) {
resolve(true);
} else {
this.router.navigate(['authenticate']);
resolve(false);
}
});
}
}
Here is an updated example:
https://stackblitz.com/edit/angular-ivy-5excpc?file=src%2Fapp%2Fapp.component.ts
Your canActivate should only take your AuthGuard class which has the resolver.
{path: 'dashboard' , component: DashboardComponent, canActivate: [AuthGuard]}

Problems to redirect to auth route Angular

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 }
];

Router Reuse Strategy breaking router

I'm trying to persist component data when user close/refresh tab or (click back/forth) using Router Reuse Strategy, but after adding CustomReuseStrategy provider routerLink stopped working properly.
After login we are redirected to '/dashboard/begin', then if i try to go '/dashboard/search' or '/dashboard/123' via routerLink the component doesn't change
However, a direct access url works well
Has anyone ever experienced this?
app.module.ts
#NgModule({
providers: [
AuthGuard,
{
provide: RouteReuseStrategy,
useClass: CustomReuseStrategy
}]
})
app.routing.ts
const ROUTES: Routes = [
{ path: 'dashboard', loadChildren: './dashboard/dashboard.module#DashboardModule', canActivateChild: [AuthGuard]},
{ path: 'login', component: LoginComponent },
{ path: '', redirectTo: '/login', pathMatch: 'full' }
]
dashboard.routing.ts
const DASHBOARD_ROUTES: Routes = [
{
path: '', component: DashboardComponent,
children: [
{
path: 'begin',
component: BeginListComponent,
},
{
path: 'search',
children: [
{path: '', component: SearchListComponent },
{path: ':id', component: SearchIdComponent}
]
}
}
]
custom.reuse.strategy.ts
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '#angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
public static handlers: { [key: string]: DetachedRouteHandle } = {};
private static waitDelete: string;
public static deleteRouteSnapshots(): void {
CustomReuseStrategy.handlers = {};
}
public static deleteRouteSnapshot(name: string): void {
if (CustomReuseStrategy.handlers[name]) {
delete CustomReuseStrategy.handlers[name];
} else {
CustomReuseStrategy.waitDelete = name;
}
}
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
console.log(route);
if (!route) {
CustomReuseStrategy.deleteRouteSnapshots();
return false;
}
if (route.params && Object.keys(route.params).length > 0) {
return false;
}
return true;
}
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
if (
CustomReuseStrategy.waitDelete &&
CustomReuseStrategy.waitDelete === this.getRouteUrl(route)
) {
CustomReuseStrategy.waitDelete = null;
return;
}
CustomReuseStrategy.handlers[this.getRouteUrl(route)] = handle;
}
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!CustomReuseStrategy.handlers[this.getRouteUrl(route)];
}
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
if (!route.routeConfig) {
return null;
}
return CustomReuseStrategy.handlers[this.getRouteUrl(route)];
}
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return (
future.routeConfig === curr.routeConfig &&
JSON.stringify(future.params) === JSON.stringify(curr.params)
);
}
private getRouteUrl(route: ActivatedRouteSnapshot) {
return route['_routerState'].url.replace(/\//g, '_');
}
}

Angular 5 page refresh always lands in the home page instead of being on the same page

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.

Categories