routerLink to route with parameters not working - javascript

I have a routerLink on my page that goes to a certain route but Im getting this error
Basically I have an asset page that has a unique id then when you click the button the id changes and the route should update so asset/sa3384320402 should then change to asset/i44309509439 the new id
my routerLink is as follows
<button [routerLink]="['/asset', newId]">click</button>
my routing page
#NgModule({
imports: [
RouterModule.forChild([
{
path: '',
children: [
{ path: 'week-1', component: Week1Component },
{ path: 'week-1/asset/:id', component: AssetPageComponent }
]
}
])
],
and my asset-page.component.ts
import { Component, OnInit, AfterViewInit } from '#angular/core';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import { ActivatedRoute, ParamMap, Router } from '#angular/router';
import { Entry } from 'contentful';
import { ContentfulService } from '../../../contentful.service';
import * as _ from 'lodash';
declare var Player: any;
declare var Vimeo: any;
#Component({
selector: 'app-asset-page',
templateUrl: './asset-page.component.html',
styleUrls: ['./asset-page.component.scss']
})
export class AssetPageComponent implements OnInit {
asset: Entry<any>[];
id: string;
videoID: string;
constructor(
private contentfulService: ContentfulService,
private route: ActivatedRoute,
private router: Router
) { }
ngOnInit() {
this.route.paramMap
.switchMap((params: ParamMap) => this.contentfulService.getAsset(params.get('id')))
.subscribe((asset) => {
this.asset = asset;
console.log(this.asset);
});
}
}
Im not sure what Is going on because if I go to that route it does work just not through the routerLink?
any help would be appreciated!
Thanks
EDIT
I have tried the following with these results
<button [routerLink]="['/week-1/asset', newId]">click</button> - same error as above
<button [routerLink]="['asset/', newId]">click</button> - just adds the new route to the end of the old route
<button [routerLink]="['asset', newId]">click</button> - just adds the new route to the end of the old route

The path you are trying to access is "/asset/:id", but your route is defined as "/week-1/asset/:id". So you either need to provide the full path to the router link, like this:
<button [routerLink]="['/week-1/asset', newId]">click</button>
or assuming you are already at the week-1 route, you can provide a relative path by omitting the first forward slash:
<button [routerLink]="['asset', newId]">click</button>

Try with this button:
<button [routerLink]="['asset/', newId]">click</button>

Related

Getting language prefix as parameter from Angular 6 router

I have an Angular (6.0.3) application and I want to use the language as a common prefix to all routes, something like /en/foo/bar. My route definition src/app/submodule/submodule.routes.ts looks like this:
export const submoduleRoutes = [
{ path: ':lingua/foo/bar', component: FooBarComponent },
];
My root component src/app/app.component.ts:
import { Component, OnInit, OnDestroy } from '#angular/core';
import { Router, ActivatedRoute, Event, NavigationEnd } from '#angular/router';
import { filter } from 'rxjs/operators';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {
title = 'app';
private sub: any;
constructor(private router: Router, private route: ActivatedRoute) {
this.router.events.pipe(
filter((event:Event) => event instanceof NavigationEnd)
).subscribe(x => console.log(x));
};
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
console.log(params);
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}
When I navigate to /xy/foo/bar, the FooBarComponent gets rendered. But I am not able to retrieve language prefix in the root component. The params hash is empty.
The console output first displays {} for the empty params, and then the NavigationEnd event.
The same code works as expected in the FooBarComponent. Obviously, the root component is the wrong place to get the parameters.
My goal is actually to get the lingua parameter for all components, so that I can set the correct language. I know that I could also store the language in a cookie or local storage but I need bookmarkable URLs for the multi-lingual content.
In case that matters, the source code is at https://github.com/gflohr/Lingua-Poly (commit 12608dc). The route in question is defined in https://github.com/gflohr/Lingua-Poly/blob/master/src/app/main/main.routes.ts (at the end, :lingua/mytest.
You need to make them children of the App.component for it to work.
For example:
const routes = [
{ path: ":lingua", component: AppComponent, loadChildren: 'app/main/main.module#MainModule' },
{ path: "", pathMatch: "full", redirectTo: "/en" }
]
This will load all the child routes from main module, but allow AppComponent to access the lingua parameter.
You will then need to remove the :lingua part from your child route
Here is a StackBlitz example

Read route params from directly entered url in app

My question would be regarding angular 4, how to get route params, if for example a user gets on your page with, instead of the default url, like for example http://localhost:3000/, to something like http://localhost:3000/user/:id, and to be able to pick up the :id from that url (user has directly entered it in the browser, not navigating through the app).
In the example bellow same component is used, mainly because of needing to catch that id and dispatch other actions, if its present, and that would be it.
I have tried playing around with ActivatedRoute but from what I could tell so far, that only works when navigation throughout the app, from within the app, not in this case, which always returns a null value if that url is directly entered in the browser, it gets redirected to the default / route and that would be it.
Any tips or pointers are much appreciated
app.routing-module.ts
import {hookComponent} from './hook.component';
import {RouterModule, Routes} from '#angular/router';
import {NgModule} from '#angular/core';
export const routes: Routes = [
{
path: '',
component: HookComponent
},
{
path: 'user/:id',
component: HookComponent
}
];
#NgModule({
imports: [RouterModule.forRoot(routes, { enableTracing: true })],
exports: [RouterModule]
})
export class AppRoutingModule {}
hook.component
import {Component, EventEmitter, Input, OnInit, ViewChild} from '#angular/core';
import { ActivatedRoute, ParamMap} from '#angular/router';
#Component({
selector: 'hook',
templateUrl: 'hook.component.html',
styleUrls: ['hook.component.scss']
})
export class HookComponent implements OnDestroy, OnInit {
constructor(private route: ActivatedRoute) {
}
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
console.log('params are', params); //null?
});
}
}
Your way is already ok, but in your example params is an array and you can access to :id by calling params['id']:
this.sub = this.route.params.subscribe(params => {
console.log('params are', params['id']);
});
Here is an working example on stackblitz.
Access current url via Location
public constructor(location:Location) {
let url = location.prepareExternalUrl(location.path());
}
and parse out id from this.
If all you want to do is log the params.id; try using the ActivatedRouteSnapshot like this.
ngOnInit() {
console.log(this.route.snapshot.params.id);
}
If you want to check if the params.id is present, maybe do something like:
import {Component, EventEmitter, Input, OnInit, ViewChild} from '#angular/core';
import { ActivatedRoute, ParamMap} from '#angular/router';
#Component({
selector: 'hook',
templateUrl: 'hook.component.html',
styleUrls: ['hook.component.scss']
})
export class HookComponent implements OnDestroy, OnInit {
hasId: boolean = false;
constructor(private route: ActivatedRoute) {
}
ngOnInit() {
if(this.route.snapshot.params.id !== null)
{
// do magic....
}
}
}

Routing child to parent is not working when navigates in Angular

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

How can I hide my Navigation Bar if the component is called on all my routes (Angular4)

I know variations of this question have been asked millions of times before but I just cant seem to solve my problem.
So i'm making an accounting site and my problem is that I cant seem to be able to hide the top navigation bar from the login page and still keep it on all my other pages/routes:
I call the Navigation Bar component in app.component.html so it shows on all my pages:
(app.component.html)
<app-navbar>
<router-outlet>
The login page has simple authentication as i'm still making the template, eventually, the username and password will come from a back-end database.
The login page ts file looks like this:
export class LoginComponent implements OnInit {
emailFormControl = new FormControl('', [Validators.required,
Validators.pattern(EMAIL_REGEX)]);
UserName = new FormControl('', [Validators.required]);
password = new FormControl('', [Validators.required]);
constructor(private router: Router) { }
ngOnInit() {
}
loginUser(e) {
e.preventDefault();
console.log(e);
const username = e.target.elements[0].value;
const password = e.target.elements[1].value;
if (username === 'admin' && password === 'admin') {
// this.user.setUserLoggedIn();
this.router.navigate(['accounts']);
}
}
}
I also have a user service:
import { Injectable } from '#angular/core';
#Injectable()
export class UserService {
private isUserLoggedIn;
public username;
constructor() {
this.isUserLoggedIn = false;
}
setUserLoggedIn() {
this.isUserLoggedIn = true;
this.username = 'admin';
}
getUserLoggedIn() {
return this.isUserLoggedIn;
}
}
I've seen answers regarding Auth and such but i can't seem to sculpt the answers around my code.
How do i hide the Navigation bar on the login page?
I'd appreciate any and all help. Thank you
EDIT
This is the routing file as requested by Dhyey:
import {RouterModule, Routes} from '#angular/router';
import {NgModule} from '#angular/core';
import { LoginComponent } from './login/login.component';
import { AdminComponent } from './Components/admin/admin.component';
import { AccountsComponent } from './Components/accounts/accounts.component';
import { MappingComponent } from './Components/mapping/mapping.component';
const appRoutes: Routes = [
{ path: '',
pathMatch: 'full',
redirectTo: 'login' },
{
path: 'login',
component: LoginComponent
},
{
path: 'admin',
component: AdminComponent
},
{
path: 'accounts',
component: AccountsComponent
},
{
path: 'mapping',
component: MappingComponent
},
];
#NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
export class AppRoutingModule {}
// export const routingComponents = [MappingComponent, AccountsComponent, AdminComponent, LoginComponent];
EDIT 2
This is the app.component.ts file
import { Component } from '#angular/core';
import {FormControl} from '#angular/forms';
import {HttpModule} from '#angular/http';
import { UserService } from './services/user.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.sass']
})
export class AppComponent {
title = 'app';
myControl: FormControl = new FormControl();
}
You can check if user is logged in through your getUserLoggedIn method:
First you need to inject UserService in app.component.ts:
constructor(public userService: UserService ) { }
Then in your html:
<app-navbar *ngIf="userService.getUserLoggedIn()">
<router-outlet>
This way only when isUserLoggedIn is true, the app-navbar will be shown
What you can also do is let your menu in app component (this is not the problem), and use a route condition to display it or not.
For that, angular provides ActivatedRoute to get info from the current route url https://angular.io/api/router/ActivatedRoute
Import ActivatedRoute or Route should be fine too
Inject in component
Using constructor :
constructor (private activatedRoute: ActivatedRoute / Route) {
this.currentPage = activatedRoute.url;
}
Then check onInit the route info like below
if (this.curentPage === 'admin') { this.displayMenu = false; }
Finally, use your <div class="menu" *ngIf="! displayMenu">...</div>

Angular 2 - How to pass URL parameters?

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']);

Categories

Resources