typescript - Angular2 Obtener parámetros del enrutador fuera de router-outlet
Tengo una aplicación de panel que consta de un componente de vista de árbol (que lista varios nodos de contenido) y un componente de edición del panel que muestra algún contenido editable dependiendo de qué rama del árbol esté seleccionada.
por ejemplo. El árbol es así:
- Football
- - Premier League
- - - Arsenal
- - - Chelsea
- - - ...etc
- - Championship
- - - Derby
- - - ...etc
Haces clic en 'Arsenal' en el árbol y se muestra algún contenido para ese equipo en un panel editable en la página.
El componente que renderiza los subcomponentes es así:
@Component({
selector: 'my-dashboard',
template: `
<div class="tree-panel-container">
<div class="tree-panel-content">
<content-tree [startNodeId]="startNodeIdContent"></content-tree>
</div>
</div>
<router-outlet></router-outlet>
`,
directives: [
ContentTreeComponent,
ContentDashboardComponent,
RouterOutlet
],
providers: [
HTTP_PROVIDERS
]
})
El contenido editable se muestra en un router-outlet para que cada pieza de contenido editable tenga su propia URL distinta, por ejemplo example.com/content/edit/123 donde 123 es el id del contenido de Arsenal, por ejemplo.
Todo esto funciona bien.
Sin embargo, lo que quiero hacer es poder acceder al parámetro de ruta id en el componente content-tree. Actualmente, estoy bastante seguro de que el código que tengo en ese componente debería funcionar:
import {Component, Input, OnInit} from '@angular/core';
import {Router, RouteParams} from '@angular/router-deprecated';
import {ContentNode} from './content-node';
import {ContentService} from '../services/content.service';
@Component({
selector: 'content-tree',
directives: [ContentTreeComponent],
template: `
<ol class="tree">
<li *ngFor="let contentNode of contentNodes" class="tree__branch" [ngClass]="{'tree__branch--has-children': contentNode.HasChildren}">
<a *ngIf="contentNode.HasChildren" (click)="contentNode.toggle=!contentNode.toggle" class="tree__branch__toggle">
{{ !!contentNode.toggle ? '-' : '+' }}
</a>
<a class="tree__branch__link" (click)="onSelect(contentNode)">{{ contentNode.Name }}</a>
<content-tree *ngIf="contentNode.toggle" [startNodeId]="contentNode.Id"></content-tree>
</li>
</ol>
<div class="error" *ngIf="errorMessage">{{errorMessage}}</div>
`
})
export class ContentTreeComponent implements OnInit {
constructor(
private _contentService: ContentService,
private _router: Router,
private _routeParams: RouteParams
) { }
errorMessage: string;
@Input('startNodeId')
private _startNodeId: number;
contentNodes: ContentNode[];
ngOnInit() {
let nodeId = +this._routeParams.get('id');
console.log('nodeId = ' + nodeId);
this.getContentNodes();
}
onSelect(contentNode: ContentNode) {
this._router.navigate( ['ContentEdit', { id: contentNode.Id }] );
}
getContentNodes() {
this._contentService.getContentNodes(this._startNodeId)
.subscribe(
contentNodes => this.contentNodes = contentNodes,
error => this.errorMessage = <any>error
);
}
}
Pero la variable nodeId en el método ngOnInit siempre se devuelve como 0.
Preguntas: ¿Es posible acceder a los parámetros de la ruta solo en un componente renderizado por un router-outlet? Si es así, ¿entonces el mejor método para manejar esto es crear un segundo (nombrado, porque ahora habrá 2) router-outlet? Si no, ¿entonces qué estoy haciendo mal?
Muchas gracias.
EDITAR:
Ahora se ha generado un Plnkr funcional (y muy feo ;)) para mostrar lo básico de la aplicación: http://plnkr.co/edit/W3PVk3Ss5Wq59IbnLjaK?p=preview. Mira los comentarios para ver lo que se supone que debe suceder...
Respuesta #1
Obtener la ruta activa desde fuera de un componente en Angular 2.1.0 y Router 3.1.0
Encontré una buena manera de obtener todos los parámetros, queryParams, segmentos y fragmentos de la ruta mostrada desde cualquier lugar dentro de tu aplicación. Simplemente agrega este código a cualquier componente donde lo necesites, o crea un servicio que pueda ser inyectado en toda tu aplicación.
import { Router, NavigationEnd } from "@angular/router";
import { Component, OnInit } from '@angular/core';
...
export class MyComponentOrService implements OnInit {
constructor(private router: Router) {}
ngOnInit() {
/* this subscription will fire always when the url changes */
this.router.events.subscribe(val=> {
/* the router will fire multiple events */
/* we only want to react if it's the final active route */
if (val instanceof NavigationEnd) {
/* the variable curUrlTree holds all params, queryParams, segments and fragments from the current (active) route */
let curUrlTree = this.router.parseUrl(this.router.url);
console.info(curUrlTree);
}
});
}
...
Respuesta #2
Esta solución funcionó para mí: ejemplo completo.
constructor(
private readonly router: Router,
private readonly rootRoute: ActivatedRoute,
){
router.events.pipe(
filter(e => e instanceof NavigationEnd),
map(e => this.getParams(this.rootRoute))
).subscribe(params => {
//
});
}
private getParams(route: ActivatedRoute): Params {
// route param names (eg /a/:personId) must be ditinct within
// a route otherwise they'll be overwritten
let params = route.snapshot.params
params = { ...route.snapshot.queryParams, ...params}
if(route.children){
for(let r of route.children){
params = {...this.getParams(r), ...params};
}
}
return params;
}
Créditos a Toxicable.
