I have a List and Details components in an application and I am trying to navigate to Details component by passing id parameter. However, there is not a reponse or error when calling the following method. I also share the routing.module:
routing.module
const routes: Routes = [
{
path: '',
component: ListComponent,
data: {...}
},
{
path: '/details/:id',
component: DetailsComponent,
data: {...}
}
];
list.component
constructor(private router: Router) {}
details(id) {
// the code hits here and get the id parameter correctly
this.router.navigate(['/details'], {
queryParams: { id: id }
});
}
details.component
constructor(private route: ActivatedRoute) { }
ngOnInit(): void {
this.route.paramMap
.subscribe(params => {
let id = +params.get('id');
});
}
So, what is wrong with this approach? The ngOnInit block of the details page is not fired.
In your route, you have specified '/details/:id' where ID is Router Param not a Query Param.
Thus, if you want to navigate to that url, use this instead:
ListComponent
this.router.navigate(['/details', id])
DetailsComponent
constructor(private route: ActivatedRoute) {}
ngOnInit() {
const id = this.route.snapshot.params.id; // Fetch the ID from your
// current route "/details/:id"
}
or you can also do it this way
ngOnInit() {
this.route.params.subscribe(params => console.log(params.id))
}
More info on Angular Router Documentation
you have to add queryParamsHandling: 'merge' to your code
details(id) {
// the code hits here and get the id parameter correctly
this.router.navigate(['/details'], {
queryParams: { id: id },
queryParamsHandling: 'merge'
});
}
Hello in the app component.html
Please add
<router-outlet></router-outlet>
Related
I've seen the same error in other posts but they didn't work for me.
I have an Angular component, where I need to read a queryParam from the url, for example in http://localhost:4200/sample-page?page=3 I want to stores the number 3 into a component local variable.
/**
* Set page by url parameter
*/
export const setPaginationMarkByUrlParam = (activatedRoute): number => {
// Get page param from Url to set pagination page
const pageParam = activatedRoute.snapshot.queryParams;
return pageParam.page ? Number(pageParam.page) : 1;
};
This function is in another file and I put as parameter the activeRoute, which comes from the ngOnInit of the component in which I want to get the queryParam.
ngOnInit() {
this.page = setPaginationMarkByUrlParam(this.activatedRoute);
}
This code works perfectly, but when the Jenkins pipeline runs the npx jest tests, I get the following message:
TypeError: Cannot read property 'queryParams' of undefined
My Spec.ts:
beforeEach(() => {
TestBed.configureTestingModule({
...,
providers: [
{
provide: ActivatedRoute,
useValue: {
data: {
subscribe: (fn: (value: Data) => void) =>
fn({
pagingParams: {
predicate: 'id',
reverse: false,
page: 0
}
})
}
}
}
]...
it('Should call load all on init', () => {
// GIVEN
const headers = new HttpHeaders().append('link', 'link;link');
spyOn(service, 'query').and.returnValue(
of(
new HttpResponse({
body: [new DataSource(123)],
headers
})
)
);
// WHEN
comp.ngOnInit();
// THEN
expect(service.query).toHaveBeenCalled();
expect(comp.dataSources[0]).toEqual(jasmine.objectContaining({ id: 123 }));
});
The test fails in comp.ngOnInit(); function.
I don't have any kind of private variables, the activeRoute that comes as a parameter, I tried it with public and private.
Looking at both StackOverflow and GitHub Issues I have not been able to fix this problem.
Thank you very much!
While you are mocking data, you are not mocking snapshot on ActivatedRoute. You have three choices to accomplish this:
First, you should consider using an ActivatedRouteStub as described in the docs. This then makes is as easy as: activatedRoute.setParamMap({page: 3}); to set any queryParameter you want to set. This option requires more test code
Next option: this would mock the queryParameter of page on the ActivatedRoute with an Observable:
provide: ActivatedRoute, useValue: {
snapshot: of(queryParams: { page: 3 }),
}
If, for a reason not disclosed in your question, you do not need an Observable from your ActivatedRoute, this would be the alternate code:
provide: ActivatedRoute, useValue: {
snapshot: { queryParams: { page: 3 } }
}
Finally, the code you provided doesn't have a call to inject for the ActivatedRoute provider nor does it show the test component creation. So at a minimum ensure you are doing that as well:
Either:
fixture = TestBed.createComponent(...);
Or:
activatedRoute = TestBed.inject(ActivatedRoute);
If none of these suggestions solve your problem, put a a minimal StackBlitz that demonstrates the problem and we'll get it working.
Generally for configuring/mocking different RouteOptions when you have ActivatedRoute with Jest you should use:
createRoutingFactory from #ngneat/spectator/jest
and pass one or more of the RouteOptions properties like (params, queryParams, parent etc.) directly on its constructor
For example:
const createComponent = createRoutingFactory({
component: Component,
imports: [RouterTestingModule],
parent: {
snapshot: {
queryParamMap: convertToParamMap({
//...
}),
paramMap: convertToParamMap({
//...
})
}
}
});
I have a multitenant application that identifies tenants based on a route parameters called organization. I have various portions of the application that need to change behavior based upon the organization passed in through the route parameter, but I'm running into some issues accessing the parameter anywhere other than the component that the router has navigated to.
In multiple areas of my application, I've placed a variant of the following code:
export class OrganizationSidebarComponent implements OnInit {
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.route.params.subscribe(params => {
console.log('[OrganizationSidebarComponent] ID IS ' + params['organization']);
console.log(params);
});
this.route.paramMap.subscribe(paramMap => {
console.log('[OrganizationSidebarComponent] ID from ParamMap: ' + paramMap.get('organization'));
});
console.log('[OrganizationSidebarComponent] ID using snapshot paramMap: ' + this.route.snapshot.paramMap.get('organization'));
console.log('[OrganizationSidebarComponent] ID using snapshot params: ' + this.route.snapshot.params.organization);
}
}
However, when the pages are navigated to, the output looks like the following:
My routes are setup like so:
const routes: Routes = [
{
path: 'Organization',
component: OrganizationsLayoutComponent,
children: [
{
path: ':organization',
component: OrganizationDashboardComponent,
canActivate: [AuthGuard]
}
]
}
];
In a perfect world, I'd be able to access the values from some injected service so that I have a centralized fetching service that I can leverage to obtain the required information, but I'm simply having issues retrieving the route parameters from anywhere that isn't the component that is being navigated to.
How can I access this information?
I would suggest to do it in another way, (based on your problem statement) instead of reading the organization in many components and loading data, read that in the app.component as below
add this method in App.component.ts
mergeRouteParams(router: Router): { [key: string]: string } {
let params = {};
let route = router.routerState.snapshot.root;
do {
params = { ...params, ...route.params };
route = route.firstChild;
} while (route);
return params;
}
then in ngOnInit do this
this.router.events.subscribe((e) => {
if (e instanceof NavigationEnd) {
const mergedParams = this.mergeRouteParams(this.router);
console.log(mergedParams);
}
});
and of course add private router: Router to your constructor
Working stackblitz
https://stackblitz.com/edit/angular-merge-route-params
Url to check https://angular-merge-route-params.stackblitz.io/dictionary/dict/code
Solution 2
Another way to get all params is using route configuration
export const routingConfiguration: ExtraOptions = {
paramsInheritanceStrategy: 'always',
};
#NgModule({
imports: [RouterModule.forRoot(routes, routingConfiguration)],
exports: [RouterModule],
})
export class AppRoutingModule { }
now if you inject route: ActivatedRoute in the params or paramsMap you will all params from parents including this child route
We are trying to use the NavigationExtras to pass data from one component to another (one page to another) like below
viewProjectDetails(e) {
const navigationExtras: NavigationExtras = {
state: {
ProjectInfo: e.data,
UserSelection: this.UserSelection
}
};
this.router.navigate(['dashboard/ProjectShipment'], navigationExtras);
}
I am trying to get the ProjectInfo and UserSelection array in to the another component
projDetail : any;
userSelection: any;
getPrjDetails() {
const navigation = this.activatedRoute.getCurrentNavigation();
const state = navigation.extras.state as {
}
Listen to the queryParams and catch the NavigationExtras
this.route.queryParams.subscribe(params => {
console.log(params["state"]);
});
constructor(private router: Router) {
console.log(this.router.getCurrentNavigation().extras.state.Projectinfo);
// should log e.data
}
You need to call getCurrentNavigation() method inside of the constructor, elsewhere the navigation has finished.
i need for advice in role based auth with https://github.com/auth0/angular2-jwt/tree/v1.0 JWT Interceptor.
How can i carry out "admin" role auth with Angular 5 ?
Now i have: after login server send back jwt token with user id in payload and using canActivate, my app check if token exist and then allow to enter secured sites.
#Injectable()
export class EnsureAuthenticated implements CanActivate {
constructor(private auth: AuthService, private router: Router) {}
canActivate(): boolean {
if (localStorage.getItem('token')) {
return true;
} else {
this.router.navigateByUrl('/login');
return false;
}
}
}
and my secure rote :
export const SECURE_ROUTES: Routes = [
{ path: 'home', component: HomeComponent, canActivate: [EnsureAuthenticated] },
{ path: 'homeadmin', component: HomeadminComponent, canActivate: [AuthenticatedAdmin] },
];
and after that I wanted to create something like that:
#Injectable()
export class AuthenticatedAdmin implements CanActivate {
constructor(private auth: AuthService, private router: Router) {}
canActivate(): boolean {
if ("in token is admin") {
return true;
} else {
this.router.navigateByUrl('/login');
return false;
}
}
}
In this approach i need decode token with https://github.com/auth0/jwt-decode
Do you think this is the correct approach? Please let me know if you have any better solution to this problem.
Yes because JWT encode your data in payload section. If you want to get some property you need decode all payload.
When you analyze code in angular2-jwt you find method in JwtHelper class to get token expiration date. In its implementation find in third line that to extract expiration date you need first decode all token payload.
Example below from angular2-jwt
public getTokenExpirationDate(token: string): Date {
let decoded: any;
decoded = this.decodeToken(token);
if (!decoded.hasOwnProperty('exp')) {
return null;
}
let date = new Date(0); // The 0 here is the key, which sets the date to the epoch
date.setUTCSeconds(decoded.exp);
return date;
}
I've tried the sample on the official page but neither it works nor the other examples on other pages work me. There are no params neither of the router nor the route export. How can I subscribe and get the parameter change?
Neither can I use the RouteParams, I got an exception there is no provider for it.
Thank you!
How am I able to do this with the current version of angular 2?
private sub: any;
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
let id = +params['id']; // (+) converts string 'id' to a number
this.service.getHero(id).then(hero => this.hero = hero);
});
}
my code:
#RouteConfig([
{ path: '/:appleId/:bananaId/fruits/...', name: 'Fruits', component: FruitsComponent }
])
How Can I get the appleId or bananaId change in the FruitsComponent?
The this.route.params does not exist :( What should I use instead?
this is the most suitable to get parameter from url
import {ActivatedRoute} from '#angular/router';
constructor(private activatedRoute: ActivatedRoute) {}
this.activatedRoute.queryParams.subscribe(params => {
let id = = params['id'];
});
Try below one:
#RouteConfig([
{
path: '/:id', name: 'Fruits', component: FruitsComponent
}
])
ngOnInit() {
this.sub = this.route.snapshot.params['id'];
if(this.sub == 'appleId/:bananaId/fruits'){
// your code
}
}