I'm developing an Angular 2 app with multiple components that rely on some data that is loaded from the server via the http-service (it's data about the user and his roles).
Most of my route components throw errors within their ngOnInit() methods if this data is not already loaded. The data is loaded and stored within a service that is injected in all components.
Is there a way to delay the rendering of the current route within my root-component until the http call is finished?
Otherwise I would have to implement some kind of check and retry mechanism within the ngOnInit of all the route components, which would be very awkward.
I already tried to hide the router-outlet element until the call finished but this leads to an error saying "Cannot find primary outlet to load xxx"
There is an option to delay of router initial navigation when creating Router module:
RouterModule.forRoot([
// routes here
], {
initialNavigation: false // the propery to delay navigation
}),
Later the initial navigation can be triggered via Angular Router, like this:
this.router.initialNavigation();
I accomplished this with a CanActivate guard. The key to making it work is returning an Observable from the canActivate method. That way, you can delay as long as you need to.
import { CanActivate } from '#angular/router';
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Rx';
import { StateService } from '../../_services/state.service';
import { Subject } from 'rxjs/Rx';
import { Subscription } from 'rxjs/Subscription';
#Injectable()
export class LoadingGuard implements CanActivate {
constructor(private state: StateService) {}
public canActivate(): Observable<boolean> {
if (!this.state.loading$.getValue()) {
return Observable.of(true);
}
let subject = new Subject<boolean>();
let subscription = this.state.loading$.subscribe(value => {
if (!value) {
subject.next(true);
subject.complete();
subscription.unsubscribe();
}
});
return subject;
}
}
Above, StateService is a service that evaluates the current user and pre-caches some data for the rest of the app. It has a subject named loading$ that returns false when loading has completed.
All that's left is to declare the guard in the app module.
import { LoadingGuard } from './app/loading-guard/loading-guard';
// other imports omitted
#NgModule({
// other module properties omitted
providers: [LoadingGuard]
})
export class AppModule {}
Then declare the guard in your routing.
import { LoadingGuard } from './app/loading-guard/loading-guard';
// other imports omitted
export const rootRouterConfig: Routes = [
{ path: 'app', component: AppComponent,
canActivate: [LoadingGuard],
children: [
{ path: 'index', component: IndexComponent },
// child routes omitted
] },
{ path: 'sign-in', component: SignInComponent },
{ path: '**', redirectTo: 'sign-in' }
];
For reference, here's the documentation on CanActivate:
https://angular.io/docs/ts/latest/api/router/index/CanActivate-interface.html
Related
I'm using angular 5.1.0, and I have an issue with the routing system, let me explain:
In my app-routing module I have an url /api that lazy loads another module, in that lazy loaded module I have the next routing implementation:
api-routing.module.ts
const routes: Routes = [
{
path: '',
component: ApisComponent,
data: {
breadcrumbs: 'APIs',
},
children: [
{
path: '',
component: ApiListComponent,
},
{
path: ':id',
component: ApiDetailComponent,
resolve: {
api: ApiResolverService
},
data: {
breadcrumbs: '{{ api.title }}',
},
},
],
},
];
The important thing here is the data param that the Router receives.
In my app I have a generic error behaviour that when an exception is throwed I have a errorHandler class that catch the error and redirects to another url: /error, this is the handler code:
import { ErrorHandler, Injectable, Injector } from '#angular/core';
import { Router } from '#angular/router';
#Injectable()
export class AppErrorHandler implements ErrorHandler {
constructor(private injector: Injector) { }
handleError(error: any): void {
const routerService = this.injector.get(Router);
routerService.navigateByUrl('/error', { skipLocationChange: true });
}
}
The problem is, when an exception is throwed inside /api and handleError is executed, I see my generic error page rendered with the breadcrumb loaded in the last route: /api by data param.
Is there any way to set the Router to reset data when is loaded? or maybe I'm doing something wrong?
UPDATE
At this point I thought the problem was due to data param, but now I see that it's not the problem. Let me show my error.component that is rendered when Router loads /error:
import { Component, OnInit } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-error',
templateUrl: './error.component.html',
styleUrls: ['./error.component.scss']
})
export class ErrorComponent implements OnInit {
constructor(private router: Router, private route: ActivatedRoute) { }
ngOnInit() {
console.log('snapshot trace');
console.log(this.route.snapshot);
}
}
I have included in the onInit component method, a trace of ActivatedRoute snapshot to see what it has, and the thing is that trace is not showing when errorHandler navigates from /api to /error.
But if I load directly /error the trace is showed, so for any reason the error component is not instanciated correctly in the first scenario (navigate from /api to /error)
UPDATE
I have upgraded to angular 5.2.9 and the problem still happens.
I have solved the problem using NgZone, I think the "timing" routing problem that angular has involve the render error component out of angular zone, so, the AppErrorHandler class looks like this:
import { ErrorHandler, Injectable, Injector, NgZone } from '#angular/core';
import { Router } from '#angular/router';
#Injectable()
export class AppErrorHandler implements ErrorHandler {
constructor(private injector: Injector) { }
handleError(error: any): void {
const routerService = this.injector.get(Router);
const ngZone = this.injector.get(NgZone);
ngZone.run(() => {
routerService.navigate(['/error'], { skipLocationChange: true });
});
}
}
Here a github issue related to my problem
Using Asp Core on Angular 4 with the default template from asp core. The guard works, but on page refresh I get unwanted behavior. When refreshing a guarded route it briefly shows my login page when canActivate is true. Image below shows this behavior. Notice on refresh the screen flashes red (my login page).
Steps to reproduce issue:
Create project with dotnet new angular
Run the dotnet restore and npm install
Add file auth.guard.ts (code below)
Add file auth.service.ts (code below)
Add login component
Add service and guard to routes in app.modal.shared.ts (code below)
Add login button on home component
Run program and click login button
Navigate to the counter route
Press F5 to refresh, the login page will appear before showing counter route (should not show login page as canActivate should be true)
Please let me know if you wish to see any additional code or if you have any questions. I have been pulling my hair out the past two days trying all kinds of things with Observables, maps and subscriptions with no results. Any help will be greatly appreciated. Thanks in advance!
auth.guard.ts
import { Injectable } from '#angular/core';
import { Router, CanActivate } from '#angular/router'
import { AuthService } from './auth.service';
#Injectable()
export class AuthGuard implements CanActivate {
constructor(
private authService: AuthService,
private router: Router) {
}
canActivate() {
if (!this.authService.isLoggedIn()) {
this.router.navigate(['/login']);
return false;
}
return true;
}
}
auth.service.ts
import { Injectable, Inject, PLATFORM_ID } from '#angular/core';
import { Router } from '#angular/router';
import { Response, Headers, RequestOptions } from '#angular/http';
import { isPlatformBrowser, isPlatformServer } from '#angular/common';
import { Observable } from 'rxjs/Rx';
import { BehaviorSubject } from 'rxjs/Rx';
#Injectable()
export class AuthService {
private baseUrl: string = '';
private loggedIn = false;
uid: string | null;
constructor(
private router: Router,
#Inject(PLATFORM_ID) private platformId: Object
) {
if (isPlatformBrowser(this.platformId)) {
this.loggedIn = !!localStorage.getItem('auth_token');
}
}
login() {
this.loggedIn = true;
localStorage.setItem('auth_token', 'test');
}
logout() {
localStorage.removeItem('auth_token');
localStorage.removeItem('uid');
window.location.replace('/home'); // redirect as we want all var and obj to reset
}
isLoggedIn() {
return this.loggedIn;
}
}
app.module.shared.ts
...
RouterModule.forRoot([
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path: 'counter', component: CounterComponent, canActivate: [AuthGuard] },
{ path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthGuard] },
{ path: '**', redirectTo: 'home' }
])
...
EDIT: Added gif of issue.
EDIT: Found out this is an issue with server-side prerendering. I am currently looking into how to setup a token storage service and pass this to the server.
The redirectTo property isn't working in my Angular 2 app. I have the following routes in my app.routing.ts:
const routes: Routes = [
{ path: '', redirectTo: '/page/1', pathMatch: 'full' },
{ path: 'page', loadChildren: 'app/modules/page/page.module#PageModule' }
]
export const routing = RouterModule.forRoot(routes);
Then, in my page.routing.ts, I have the following:
const pageRoutes: Routes = [
{ path: ':id', component: PageComponent, canActivate: [LoginGuard] }
];
export const pageRouting = RouterModule.forChild(pageRoutes);
Every time I access the home page it displays the LoginComponent for a second, then it disappears. However, it should redirect to the PageComponent.
Why isn't that happening? Why the LoginComponent is being loaded (even if it's only for a brief second) if the user is already logged in?
Here's my LoginGuard:
#Injectable()
export class LoginGuard implements CanActivate {
constructor(private af: AngularFire, private router: Router) {}
canActivate(): Observable<boolean> {
return this.af.auth.map(auth => {
if (auth === null) {
this.router.navigate(['/login']);
return false;
} else {
return true;
}
}).first();
}
}
EDIT: Temporarily, I changed the LoginComponent to redirect to the PageComponent if a user is logged in. I still wonder, though, why redirectTo isn't working.
I don't know exactly why this is happening, but I believe if you check the LoginGuard before the PageModule loads, it will work.
app.routing.ts
const routes: Routes = [
{ path: '', redirectTo: '/page/1', pathMatch: 'full' },
{
path: 'page',
// Call the guard before the module is loaded
canLoad: [ LoginGuard ]
loadChildren: 'app/modules/page/page.module#PageModule'
}
]
export const routing = RouterModule.forRoot(routes);
LoginGuard
#Injectable()
export class LoginGuard implements CanActivate, CanLoad {
constructor(private af: AngularFire, private router: Router) {}
// Add this method to validade the canLoad
canLoad(route: Route): Observable<boolean> {
return this.canActivate();
}
canActivate(): Observable<boolean> {
return this.af.auth.map(auth => {
if (auth === null) {
this.router.navigate(['/login']);
return false;
} else {
return true;
}
}).first();
}
}
You should NOT navigate inside a Guard
This is happening because you call this.router.navigate(['/login']); directly from your route guard which initializes a new route navigation on top of the one currently running.
You create a "race" between two navigations; my guess is the one to /login' wins because the other one has to lazy load the module (takes some time). But after the loading is done, it changes to that route afterwards, hence the "flashing" login popup.
You should NOT navigate inside a Guard, instead you should always return either a boolean (to allow navigate true/false) or a UrlTree if you want to redirect/change the route. The Guard returns the value and the router will then change navigation to the provided UrlTree for you inside the ongoing/triggered navigation and you won't get any race.
So change your method like this, and it will work correct.
canActivate(): Observable<boolean|UrlTree> {
return this.af.auth.map(auth => {
if (auth === null) {
return this.router.parseUrl('/login');
}
return true;
}).first();
}
You should see it like this, if you would call this.router.navigate in several route guards then the router wouldn't know where to navigate to, by returnin a UrlTree this problem is resolved. See also a related question/answer here
I would like to create an external redirect, but to make all routes consistent I think it would be nice to do everything(including external redirects) under Router States configuration.
so:
const appRoutes: Routes = [
{path: '', component: HomeComponent},
{path: 'first', component: FirstComponent},
{path: 'second', component: SecondComponent},
{path: 'external-link', /*would like to have redirect here*/}
];
UPD: and I don't want to use empty component for this case like #koningdavid suggested. This solution looks really weird for me. It should be something really easy to implement for such case, without virtual components.
You can achieve what you want with a trick using the resolve option of a route. Resolve is some data value that Angular2 will obtain for the route to be initialized. More details you can find here in the official documentation.
I have tried this approach and it does work. Example:
Add this to the provider section (plus import the required classes from Routing)
#NgModule({
providers: [
{
provide: 'externalUrlRedirectResolver',
useValue: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) =>
{
window.location.href = (route.data as any).externalUrl;
}
}
]
})
Then you can define your route like this:
{
path: 'test',
component: AnyRandomComponent,
resolve: {
url: 'externalUrlRedirectResolver'
},
data: {
externalUrl: 'http://www.google.com'
}
}
This will redirect to the external URL. It's a bit of a hackish way really. I tried to achieve the result without using the component at all, but you have to use either redirectTo or component or children or loadChildren. redirectTo won't trigger the resolve and I am not sure about children, though you can experiment.
You can implement it in a nice class rather than direct function in provider. More info in the documentation (see reference above).
P.S. I would really rather use a redirect component myself I think. Just use the trick with the data and getting the state from the router with externalUrl to get this as a parameter.
You can create a RedirectGuard:
import {Injectable} from '#angular/core';
import {CanActivate, ActivatedRouteSnapshot, Router, RouterStateSnapshot} from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class RedirectGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
window.location.href = route.data['externalUrl'];
return true;
}
}
Import it in app.module:
providers: [RedirectGuard],
And define your route:
{
path: 'youtube',
canActivate: [RedirectGuard],
component: RedirectGuard,
data: {
externalUrl: 'https://www.youtube.com/'
}
}
As far as I know NG2 router doesn't support external redirecting. You could create a redirect component as a workaround.
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'redirect',
template: 'redirecting...'
})
export class RedirectComponent implements OnInit {
constructor() { }
ngOnInit() {
window.location.href = 'http://www.redirecturl.com'
}
}
And use that in your routing
{ path: 'login', component: RedirectComponent, pathmath: 'full'},
Hmm...
I think you can simply request the URL instead of calling ng2 Router...
For example...
External
instead of
<a routerLink="/someRoute" routerLinkActive="active">External</a>
OR
window.location.href = 'http://www.example.com'
instead of
this.router.navigate( [ '/someRoute', 'someParam' ] );
Right...?
just use:
{
path: 'external-link',
loadChildren: () => new Promise( () => { if(window.location.href.match(/external-link/) ) window.location.href = 'https://external-link.com/'; } )
},
The Router can't redirect externally. An external resource can't be a state of the app.
If it's only for clarity, keeping all the routes visible in the one spot, you could define another constant array with all the external paths in the same file as the routes.
I assume you don't wanna create a component for every single url, which is why you are looking to do it without a component...
So you can try creating a function that generates the component object for you...
For example...
function generateLinkingComponent( url ) {
// Generate your component using koningdavid's code
// replace 'http://www.redirecturl.com' with url param
// and return it...
}
And add it like this in your router config...
const appRoutes: Routes = [
{path: '', component: HomeComponent},
{path: 'first', component: FirstComponent},
{path: 'second', component: SecondComponent},
{path: 'external-link', component: generateLinkingComponent( 'http://example.com' )},
{path: 'client-login', component: generateLinkingComponent( 'http://client-login.example.com' )},
{path: 'admin-login', component: generateLinkingComponent( 'http://admin.example.com' )},
];
This will be easy with JS... but not sure how one can return a class in a function in typeScript...
Hope that helps...
Wrapping up Ilya's answer:
Add this module.
import { Component, Injectable, NgModule } from '#angular/core';
import { ActivatedRouteSnapshot, Resolve } from '#angular/router';
#Component({
template: ''
})
class ExternalLinkComponent {
constructor() {
}
}
#Injectable()
class ExternalLinkResolver implements Resolve<any> {
resolve(route: ActivatedRouteSnapshot): any {
window.location.href = route.data.targetUri;
return true;
}
}
export class ExternalRoute {
data: {
targetUri: string;
};
path: string;
pathMatch = 'full';
resolve = { link: ExternalLinkResolver };
component = ExternalLinkComponent;
constructor(path: string, targetUri: string) {
this.path = path;
this.data = { targetUri: targetUri };
}
}
#NgModule({
providers: [ ExternalLinkResolver ],
declarations: [ExternalLinkComponent]
})
export class ExternalRoutesModule { }
Then import ExternalRoutesModule and add instances of ExternalRoute.
const childRoutes: Routes = [
new ExternalRoute('', '/settings/account'),
{ path: 'staff-profiles', component: StaffProfilesComponent},
{ path: 'staff-assignments', component: StaffAssignmentsComponent}
];
const routes: Routes = [
{ path: '', component: BaseComponent, children: childRoutes }
];
#NgModule({
imports: [ ExternalRoutesModule, RouterModule.forChild(routes) ],
exports: [ RouterModule ]
})
export class SettingsRoutingModule { }
Note I'm mounting the submodule routes via loadChildren in this example.
You can use the NavigationEnd event.
import { NavigationEnd, Router } from '#angular/router';
app.component.ts
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
if (event.url.includes('faq')) {
// open in the same tab:
window.location.href = 'https://faq.website.com';
// open a new tab:
// window.open('https://faq.website.com', '_blank');
// and redirect the current page:
// this.router.navigate(['/']);
}
}
});
P.S. Don't forget to remove your route from the AppRoutingModule.
Here is a code that should work for you without a lot of issues. FYI the router events error handler can be put anywhere irrespective of placement in the component.
app.component.html
Angular Port is in 4200
<a routerLink="/test">Main Link - 1</a> |
<a [routerLink]="getLinkWithExternal({url: '/test', external:false})">Other Link - 1a</a> |
<a [routerLink]="getLinkWithExternal({url: 'http://localhost:4211', external:true})">Other Link - 1b</a> |
<a [routerLink]="getLink({url: '/test'})">Other Link - 1a</a> |
<a [routerLink]="getLink({url: 'http://localhost:4211'})">Other Link - 1b</a> |
<a style="cursor: pointer; text-decoration: underline;" (click)="routeLink('/test')">Other Link - 1c</a> |
<a style="cursor: pointer; text-decoration: underline;" (click)="routeLink('http://localhost:4211')">Other Link - 1d</a>
<router-outlet></router-outlet>
app.component.ts
import { Component } from '#angular/core';
import { NavigationEnd, Router } from '#angular/router';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
constructor(private router: Router) { }
// RECOMMENDATION - Add following in menus of each microservice (individual and different)
// external: true
// Will make it a better menu structure for each microservice
// If Single and same menu for all microservices then remove external === true
// Logic One
getLinkWithExternal(sidebarnavLink: any) {
this.router.errorHandler = function (error: any) {
if (!sidebarnavLink.url.includes(window.location.origin.toString()) && sidebarnavLink.url.includes("http") && sidebarnavLink.external === true) {
window.location.href = sidebarnavLink.url.toString();
return true;
}
return null;
}.bind(sidebarnavLink);
return [sidebarnavLink.url];
}
getLinkWithExternalWithEventSubscribe(sidebarnavLink: any) {
this.router.events.subscribe(function (event) {
if (event instanceof NavigationEnd) {
if (event.url.includes('http')) {
if (!sidebarnavLink.url.includes(window.location.origin.toString()) && sidebarnavLink.url.includes("http") && sidebarnavLink.external === true) {
window.location.href = sidebarnavLink.url.toString();
return true;
}
return this.router.navigateByUrl(sidebarnavLink.url);
// return this.router.navigate([sidebarnavLink.url]);
}
return this.router.navigateByUrl(sidebarnavLink.url);
// return this.router.navigate([sidebarnavLink.url]);
}
}.bind(sidebarnavLink))
}
getLinkWithExternalImplementationTwoWithNoRouteError(sidebarnavLink: any) {
if (!sidebarnavLink.url.includes(window.location.origin.toString()) && sidebarnavLink.url.includes("http") && sidebarnavLink.external === true) {
window.location.href = sidebarnavLink.url.toString();
return true;
}
return [sidebarnavLink.url];
}
// Logic Two
getLink(sidebarnavLink: any) {
this.router.errorHandler = function (error: any) {
if (!sidebarnavLink.url.includes(window.location.origin.toString()) && sidebarnavLink.url.includes("http")) {
window.location.href = sidebarnavLink.url.toString();
return true;
}
return null;
}.bind(sidebarnavLink);
return [sidebarnavLink.url];
}
// Logic Three
routeLink(lnk: any) {
if (lnk.includes("http")) {
console.log("Test");
window.location.href = lnk;
return true;
}
return this.router.navigateByUrl(lnk);
// return this.router.navigate([lnk]);
}
}
I have created a single page mortgage calculator application in Angular 2, which acts like a learning playground for me (trying to get more accustomed to technology stack currently used at work)... It's running at http://www.mortgagecalculator123.com if you want to look at it. I've made it open source with a Fork Me link right on the page if you want to look at it.
Anyhow, what I want to do, is to be able to pass variables to my app, straight from the URL, so they can be consumed by my Angular 2 app. Something like this: http://www.mortgagecalculator123.com/?var1=ABC&var2=DEF
I've tried following, in my app.component.ts, I've added following:
import { Router, ActivatedRoute, Params } from '#angular/router';
AppComponent {
private var1: string;
private var2: string;
constructor(
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
this.route.params.forEach((params: Params) => {
this.var1 = params['var1'];
this.var2 = params['var2'];
});
console.log(this.var1, this.var2);
}
...
}
But this won't work, when I run npm start, I get following error:
aot/app/app.component.ngfactory.ts(45,30): error TS2346: Supplied parameters do not match any signature of call target.
Thank you, any help would be much appreciated.
I created a pull request with the query params working. I will try to explain everything I did.
The reason why the previous answers doesn't work is because you aren't using the router at all. You created a massive app component without routes. To fix that we need to start using the route module, I also advise you to read these two tutorials: Routing and Routing & Navigation.
First we need to change your index.html, add this to your <head>:
<base href="/">
See here why it's important to add that.
Then since you are using your AppComponent to show everything we need to create a new component, which we will call RootComponent. On your index.html change <my-app> to <root>; it will look like this:
<root>Loading...</root>
Now inside your app folder we need to create two files the first one will be root.component.ts which will look like this:
import { Component } from '#angular/core';
#Component({
selector: 'root',
template: `<router-outlet></router-outlet>`,
})
export class RootComponent {
constructor() { }
}
Look that we have the <router-outlet></router-outlet> as a template, Angular will inject our components based on the route.
We still need to create one more file, which will be main.route.ts, this is what it looks like:
import { Routes, RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
export const mainRoutes: Routes = [
{ path: '', component: AppComponent }
];
export const mainRoutingProviders: any[] = [];
export const routing = RouterModule.forRoot(mainRoutes);
In this file we are saying that for our base route, we want to render our AppComponent
We have created our new files, now we need to tell our App Module about them, in your app.module.ts so we import the new files and declare the new component. We also need to change our boostrap component:
import {NgModule} from '#angular/core';
import {BrowserModule} from '#angular/platform-browser';
import {FormsModule, ReactiveFormsModule} from "#angular/forms";
import {AppComponent} from './app.component';
import {RootComponent} from './root.component'; // we import our new RootComponent
import {ChartModule} from 'primeng/primeng';
import {TooltipModule} from 'primeng/primeng';
import { routing, mainRoutingProviders } from './main.routes'; // We also import our Routes
#NgModule({
imports: [
BrowserModule,
ChartModule,
FormsModule,
mainRoutingProviders, // we also need to import our route provider into the module
ReactiveFormsModule,
routing, // and also import our routes declarations
TooltipModule
],
declarations: [AppComponent, RootComponent], // we declare our new RootCpmponent
bootstrap: [RootComponent] // Notice that we are now using our RootComponent to bootstrap our app
})
export class AppModule {
}
Now with all this in place we can now finally start passing parameters to our app, on your AppComponent import the Router, ActivatedRoute and the Params from #angular/router so your AppComponent will look something like this:
import { Component, OnDestroy, OnInit } from '#angular/core';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { Subscription } from 'rxjs/Subscription';
export class AppComponent implements OnInit, OnDestroy {
private var1: string;
private var2: string;
private sub: Subscription;
constructor(
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
// assign the subscription to a variable so we can unsubscribe to prevent memory leaks
this.sub = this.route.queryParams.subscribe((params: Params) => {
this.var1 = params['var1'];
this.var2 = params['var2'];
console.log(this.var1, this.var2);
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
...
}
You can see the pull request here
It seems you are dealing with Queryparams . So to access them, you can try below code,
this.var1= this.route
.queryParams
.map(params => params['var1']);