Angular router get child param from root component - javascript

I have this structure in my app.component.html:
<app-main-nav></app-main-nav>
<router-outlet></router-outlet>
This is my routes:
const routes = [
{path: "", redirectTo: "home", pathMatch: "full"},
{
path: "posts", component: PostsComponent,
children: [{
path: ":id",
component: PostComponent
}];
}
]
I am trying to access the params from the PostComponent page in my MaiNavComponent but it throws an error.
export class MainNavComponent implements OnInit {
constructor( private route: ActivatedRoute) {
route.params.subscribe(console.log)
}
}
How can I get the :id of the PostComponent from the MainNavComponent?
I tried to do this:
route.params.subscribe(console.log)
Here I get an empty object.
And this:
route.firstChild.params.subscribe(console.log)
Cannot read property 'params' of null

The problem is that ActivatedRoute only available inside components loaded in an outlet (route-outlet). In the outer components you can inject the router and use it as follow:
export class MainNavComponent implements OnInit {
constructor(private router: Router) {}
ngOnInit() {
// Fires when the url changes
this.router.events.subscribe(data => {
// Only handle final active route
if (data instanceof NavigationEnd) {
// parsedUrl conatins params, queryParams
// and fragments for the active route
let parsedUrl = this.router.parseUrl(this.router.url);
console.log(parsedUrl);
}
});
}
}
I hope this will help you.

constructor(
private router: Router,
private activatedRoute: ActivatedRoute) {
}
ngOnInit() {
this.loadParams();
}
private loadParams(): void {
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
let activatedRoute = this.activatedRoute.firstChild;
while (!activatedRoute) {
activatedRoute = activatedRoute.firstChild;
}
const value = activatedRoute.snapshot.paramMap.get('parmeter key');
}
});
}

You have to snapshot to get ID from the URL.Uodate constructor with below
constructor( private route: ActivatedRoute) {
}
ngOnInit() {
// (+) converts string 'id' to a number
let id = +this.route.snapshot.params['id'];
}

Related

Angular how to call Method from Sibling Component that is binded via <router-outlet>?

I have a Project that uses HTTP Calls to fetch Data from API Endpoint and than display on Screen.
It's a simple ToDoList. So you can add Items to the list, see all Items in your List, delete items and so on.
The Project structure is this:
Items-Component (Holds the entire App basically)
Item-list-component
Item-detail-component
Item-edit-component
item-add-component
Item.service
The Items.component.html looks like this:
<div class="row">
<div class="col-md-5">
<app-item-list></app-item-list>
</div>
<div class="col-md-7">
<router-outlet></router-outlet>
</div>
So we can see that the item-list-component and the other 3 components (binded via router-outlet) are sibling components, that's what I think.
So my Problem is now:
I want that whenever a new Item is created the items[] in the items.list component should refresh automatically. Now I must click a "Fetch Items" button to refresh the items[].
When I add a new Item, it fires a method from my item.service, it holds a fetchItems Method that just returns an Observable of the API Endpoint, like this:
Item-add component.ts:
#Component({
selector: 'app-item-add',
templateUrl: './item-add.component.html',
styleUrls: ['./item-add.component.css']
})
export class ItemAddComponent implements OnInit {
constructor(private itemService: ItemService, private route: ActivatedRoute, private router: Router) { }
ngOnInit(): void {
}
onCreatePost(item: Item) {
// Send Http request
this.itemService.createAndStorePost(item.description, item.isComplete);
//Here I want that the items[] in the items.list component refreshes when I add new Item
this.onCancel();
}
onCancel() {
this.router.navigate([''], {relativeTo: this.route});
}
}
And the item.service.ts:
#Injectable()
export class ItemService {
constructor(private http: HttpClient, private route: ActivatedRoute, private router: Router) {
}
fetchItems(): Observable<Item[]> {
return this.http.get<Item[]>('https://localhost:44321/api/TodoItems');
}
fetchItem(id: number): Observable<Item> {
return this.http.get<Item>('https://localhost:44321/api/TodoItems' + '/' + id);
}
createAndStorePost(description: string, isComplete: boolean) {
var item = { description: description, isComplete: isComplete };
this.http.post('https://localhost:44321/api/TodoItems', item)
.subscribe(Response => {
});
}
deleteItem(id: number): Observable<Item> {
return this.http.delete<Item>('https://localhost:44321/api/TodoItems' + '/' + id);
}
updateItem(id:number, item: Item) {
this.http.put<Item>('https://localhost:44321/api/TodoItems' + '/' + id, item).subscribe();
}
}
Then the items-list component catches that Observable and subscribes to it and sets the Response from that subscription to and items[] in the component itself:
#Component({
selector: 'app-item-list',
templateUrl: './item-list.component.html',
styleUrls: ['./item-list.component.css']
})
export class ItemListComponent implements OnInit {
items: Item[] = [];
constructor(private route: ActivatedRoute, private router: Router, private itemService: ItemService) { }
ngOnInit(): void {
this.onFetchItems();
}
onFetchItems() {
this.itemService.fetchItems().subscribe(Response => {
this.items = Response;
});
}
onNewItem() {
this.router.navigate(['new'], {relativeTo: this.route});
}
}
What can I do to trigger that the items.list should fetch Items again?
I can't use #ViewChild because it is no Parent-Child relation.
Can I implement and instance of item.list anywhere in the project and just call the onFetchItems Method?
Thanks!
you can use BehaviorSubject to share data between your different components.
Here is an example:
In your ItemService.
import { BehaviorSubject } from 'rxjs';
#Injectable()
export class ItemService {
private _itemsSource = new BehaviorSubject([]);
currentItems = this._itemsSource.asObservable();
constructor() { }
updateItems(items: []): void {
this._itemsSource.next(items)
}
}
In your ItemsComponent, you update the new value in the service after you get all the items,
#Component({
selector: 'app-item',
templateUrl: './item.component.html',
styleUrls: ['./item.component.css']
})
export class ItemComponent implements OnInit {
items: Item[] = [];
constructor(private itemService: ItemService) { }
ngOnInit(): void {
this.onFetchItems();
}
onFetchItems() {
this.itemService.fetchItems().subscribe(Response => {
this.items = Response;
this.updateItems(this.items)
});
}
updateItems(newItems: []): void {
this.itemService.updateItems(newItems)
}
}
And in your ItemListComponent
#Component({
selector: 'app-item-list',
templateUrl: './item-list.component.html',
styleUrls: ['./item-list.component.css']
})
export class ItemListComponent implements OnInit {
items: Item[] = [];
subscription: Subscription;
constructor(private route: ActivatedRoute,
private router: Router,
private itemService: ItemService) { }
ngOnInit(): void {
this.subscription = this.itemService.currentItems.subscribe(items => this.items = items)
}
onNewItem() {
this.router.navigate(['new'], {relativeTo: this.route});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}

how can i find paramter of previous route in angular

i want find the params in previous route in angular typescript .
i use this code :
private previousUrl: string = undefined;
private currentUrl: string = undefined;
constructor(private router: Router) {
this.currentUrl = this.router.url;
router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
this.previousUrl = event.url;
this.currentUrl = this.currentUrl;
}
});
}
but i can not access to the params of this url :
http://localhost:4200/claims-manager/200/edit
i want ti access 200 . how can i find params in url ????
You can do it in your component file but It is a best practice to do it in a service (using rxjs) to pass data and call it in your component file
In your service
export class myService {
constructor() { }
private param = new BehaviorSubject("");
sharedParam = this.param.asObservable();
paramToPass(param:string) {
this.param.next(param)}
}
In your component class that set param
export class ComponentSetParam {
param: string
constructor(private myService: Service)
this.myService.setParam(this.param);
}
in your appModule
#NgModule({
declarations: [YourComponents]
imports: [ AppRoutingModule, YourModules...],
providers: [ShareService],
})
export class AppModule {}
Component that you want to pass data
export class ComponentGetParam {
paramFromService: string
constructor(private myService: Service) {
this.shareService.sharedData.subscribe(data : string => {
this.paramFromService = data;
})
}
}
Try this:
readonly _destroy$: ReplaySubject<boolean> = new ReplaySubject<boolean>(1);
constructor(
private activatedRoute: ActivatedRoute,
) {
this.activatedRoute.parent.paramMap
.pipe(
distinctUntilChanged(),
takeUntil(this._destroy$)
)
.subscribe((params: ParamMap) => {
const id = params.get('id');
});
}
ngOnDestroy() {
this._destroy$.next(true);
this._destroy$.complete();
}
Where 'id' is a name, that you use in the routing, e.g.
path: '/claims-manager/:id/'
Demo You can do it in service
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
#Injectable()
export class ShareService {
constructor() { }
private paramSource = new BehaviorSubject("");
sharedData = this.paramSource.asObservable();
setParam(param:string) { this.paramSource.next(param)}
}
in constructors
constructor(private shareService: ShareService)
in component in ngOnDestroy set this like this.shareService.setParam(param);
in appmodule
providers:[ShareService ]
in new component in ngOnInit or in constructor get like
this.shareService.sharedData.subscribe(data=> { console.log(data); })

Redirect the user before component gets loaded

I would like to redirect the user to the homepage if there is no cookie set.
My problem is that the user may be redirected but it takes too long. For about 1 second they are still able to see the protected page. How can I prevent this?
ngOnInit() {
this.hasAccess().then(result => {
if (!result) {
this.router.navigate(['/']).then();
}
});
}
private hasAccess() {
return new Promise(resolve => {
this.login.hasCookie(this.cookieService.get('login')).subscribe(hasCookie => {
if (hasCookie === 1) {
return new Promise(() => {
this.login.getCookie().subscribe(cookieFromServer => {
if (cookieFromServer === this.cookieService.get('login')) {
return resolve(true);
} else {
return resolve(false);
}
});
});
}
return resolve(false);
});
});
I have also tried to run my function hasAccess() in constructor() instead of ngOnInit() but the problem remains the same.
You should use route guards. They check if the routes can be visited or not before the route loads its content.
#Injectable()
export class CookieGuard implements CanActivate {
constructor(
private cookieService: CookieService,
private login: LoginService
) {}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this.login.hasCookie(this.cookieService.get('login'));
}
}
From your notes it is not clear what this.login is, you'll need to adjust that to fit your setup. Then you can configure your route with the following guard:
const routes: Route[] = [
{ path: '/whatever', component: WhateverComponent, canActivate: [CookieGuard] }
];
You can use Angular gurad.
#Injectable({
providedIn: 'root'
})
export class YourGuard implements CanActivate {
path: ActivatedRouteSnapshot[];
route: ActivatedRouteSnapshot;
constructor(private auth: AuthenticationService, private router: Router) { }
canActivate() {
if (your logic) {
....
}
else redirect to ...
}
in your routing.module :
{
path: 'your path',
loadChildren: () => import('path')
.then(m => m.YorModule),
canActivate:[YourGuard]
},
Use a RouteGuard like this:
export class ComponentRouteGuard implements CanActivate {
constructor(private router: Router) { }
canActivate(route: ActivatedRouteSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if (this.isCookieSet) {
return true;
} else {
this.router.navigate([`unauthorized`]);
return false;
}
}
}
Routes:
export const routes: Routes = [
{ path: 'test', component: YourComponent, canActivate: [ComponentRouteGuard]},
{ path: 'unauthorized', component: UnAuthorizedComponent }
];

share data from service to component after render the function in angular 4

i have service, in service, I have a "cohortTabsResult" method whitch sets the charts array. i want to use this arry in "chart.component"
export class CohortService {
public charts: Array<any>;
cohortTabsResult(obj){
this.charts = []
const subscription = this.cohortDataReq(obj).subscribe(res => {
if(res.status !== 500){
const dataObj = {
definedChart: obj.graph_type,
definedChartData: []
};
this.charts.push(dataObj);
const response = res.json()
//console.log(response)
if (response.error) {
//this.isLoaded = false;
}
else{
Array.prototype.forEach.call(response.data, dataRes => {
const newData = this.getChartDataFormat(dataRes, obj.graph_type, "userType")
dataObj.definedChartData = _.cloneDeep(newData);
});
}
}
});
}
}
and this is my chart.component here I am getting the empty array.
export class ChartCohortComponent implements OnInit{
charts: any;
constructor(private cohortService: CohortService, private route:
Router, public activatedRoute: ActivatedRoute) {
this.charts = this.cohortService.charts;
}
ngOnInit(){
console.log("ch", this.charts)
}
}
import CohortService to your component, add it to the providers in #component, now you can access the variables inside the service. :D
import { CohortService } from '../../cohort.services'; // whatever the path is..
#Component({
selector: '',
templateUrl: '',
styleUrls: [''],
providers: [CohortService]
})
export class ChartCohortComponent implements OnInit{
charts: any;
constructor(private cohortService: CohortService, private route:
Router, public activatedRoute: ActivatedRoute) {
this.charts = this.cohortService.charts;
}
ngOnInit(){
console.log("ch", this.charts)
}
}

Angular 2, How to display current route name? (router 3.0.0-beta.1)

I want to display the name of the route in the app.component.html template. I'm looking for a simple solution, something that can be written like this:
{{router.currentRoute.name}}
My current router config:
export const routes: RouterConfig = [
{
path: '',
redirectTo: '/catalog',
pathMatch: 'full'
},
{
path: 'catalog',
name: 'Catalog', // Is this property deprecated?
component: CatalogComponent
},
{
path: 'summary',
name: 'Summary',
component: SummaryComponent
}
];
If your routes are configured with your route name in the data property like this:
{
path: 'somepath',
component: SomeComponent,
data: {
name: 'My Route Name'
}
}
In your app.component.ts you can import 'rxjs/add/operator/filter'; + import { ActivatedRoute, Router, NavigationEnd } from '#angular/router'; and do the following:
constructor(
private route: ActivatedRoute,
private router: Router
) { }
ngOnInit() {
this.router.events
.filter(event => event instanceof NavigationEnd)
.subscribe(event => {
let currentRoute = this.route.root;
while (currentRoute.children[0] !== undefined) {
currentRoute = currentRoute.children[0];
}
console.log(currentRoute.snapshot.data);
})
}
This will listen for NavigationEnd events and then traverse down to the current route so that you can access the data of that route.
If you are on /somepage using the code above, it should print { name="My Route Name"} in your console.
constructor(
private route: ActivatedRoute,
private router: Router
) { }
ngOnInit() {
this.router.events.pipe(
.filter(event => event instanceof NavigationEnd)).subscribe(event => {
let currentRoute = this.route.root;
while (currentRoute.children[0] !== undefined) {
currentRoute = currentRoute.children[0];
}
console.log(currentRoute.snapshot.data);
});
}```
try this if anybody facing issue with filter

Categories

Resources