Need help accessing variable from Service in Angular 2 - javascript

Passing the URL id from the last page a user was on to a service that I can reference in a dialog.
issuer.service.ts
import { Injectable, EventEmitter } from '#angular/core';
import { Observable, of } from 'rxjs';
import { BehaviorSubject } from 'rxjs';
#Injectable()
export class IssuerService {
private urlidSource = new BehaviorSubject<string>('');
currentUrlid = this.urlidSource.asObservable();
public onChange: EventEmitter<string> = new EventEmitter<string>();
constructor () {
}
changeUrlid(urlid: string) {
this.currentUrlid = of(urlid);
this.onChange.emit(urlid);
}
getUrlid(currentUrlid: string) {
return this.currentUrlid;
}
}
Page that has the URL id I want (dashboard.component.ts)
import { IssuerService } from './../../issuer.service';
import { ActivatedRoute } from '#angular/router';
import { Router } from '#angular/router';
urlid: string;
constructor(
private route: ActivatedRoute,
private router: Router,
private issuerService: IssuerService,
public dialog: MatDialog
) {}
newUrlid() {
this.issuerService.changeUrlid(this.route.snapshot.paramMap.get('id'));
console.log(this.urlid);
}
ngOnInit() {
// Get URL ID
this.issuerService.onChange.subscribe(urlid => this.urlid = urlid);
this.newUrlid();
}
Component I want to read the value in:
import { ActivatedRoute } from '#angular/router';
import { Router } from '#angular/router';
import { IssuerService } from './../../issuer.service';
urlid: string;
constructor(
private route: ActivatedRoute,
private router: Router,
private issuerService: IssuerService,
public dialog: MatDialog
) {}
ngOnInit() {
this.issuerService.onChange.subscribe(urlid => {
this.urlid = urlid;
console.log(this.urlid);
});
}
So currently when I visit my dashboard page it will display the value of 2 which is correct. My goal is that when a user visits any page I can read this value of 2. How can I access this value? The above code works and my Header displays 2 but only when on the dashboard page. I need it to display 2 no matter what page the user is on.

you can see this example, and It's modified list:
use queryPamas to get query string, not params (DashboardComponent)
use ReplaySubject(1) to return the last urlId; it's don't have a default value, just return prev one value (IssuerService)
get observable from getUrlid and subscribe it in components that want to show url id
export class IssuerService {
private urlidSource = new ReplaySubject<string>(1);
constructor() {
}
changeUrlid(urlid: string) {
this.urlidSource.next(urlid);
}
getUrlid() {
return this.urlidSource;
}
}
export class DashboardComponent implements OnInit {
urlid: string;
constructor(
// private route: ActivatedRoute,
private router: Router,
private issuerService: IssuerService,
// public dialog: MatDialog
) { }
newUrlid() {
// Get URL ID
this.route.queryParams.subscribe((queryParam) => {
const id = queryParam['id'];
if (!id) {
return;
}
this.issuerService.changeUrlid(id);
});
}
ngOnInit() {
this.newUrlid();
this.issuerService.getUrlid().subscribe(urlid => {
this.urlid = urlid;
});
}
}
export class HelloComponent implements OnInit {
urlid;
constructor(
private issuerService: IssuerService
) { }
ngOnInit() {
this.issuerService.getUrlid().subscribe(urlid => {
this.urlid = urlid;
});
}
}

You do not need a parameter for your get Method since you already have the value inside the service,
getUrlid() {
return this.currentUrlid;
}
and you can use retrieve the value in the 2nd component as follows,
this.issuerService.currentUrlid.subscribe((value: string) => {
this.urlid = value;
}

Related

Have realtime updates for a single Firestore document

There is a lot of documentation and examples of firestore collections getting realtime updates. However, there is very little for those who wish to have a single document have real time updates. I want to have a single document (an item), on a page where only the item will be viewed and manipulated and any changes to document, will have realtime updating.
Here is my component that wants to do stuff with the item:
import { Component, OnInit } from '#angular/core';
import { ItemsService } from '../shared/items.service';
import { ActivatedRoute, Router } from '#angular/router';
#Component({
selector: 'app-view-item',
templateUrl: './view-item.component.html',
styleUrls: ['./view-item.component.css']
})
export class ViewItem implements OnInit {
item;
private sub: any;
constructor(
// Service used for Firebase calls
private itemsService: ItemsService,
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
// Item retrieved from */item/:id url
this.sub = this.route.params.subscribe(params => {
this.getItem(params['id']);
});
}
getItem = (id) => {
this.itemsService.getItem(id).subscribe(res => {
console.log(res);
this.item = res;
console.log(this.item);
});
}
And the service it uses for calls:
import { Injectable } from '#angular/core';
import { AngularFirestore, AngularFirestoreDocument } from '#angular/fire/firestore';
#Injectable({
providedIn: 'root'
})
export class ItemsService {
constructor(
private firestore: AngularFirestore
)
getItem(id) {
return this.firestore.collection('items').doc(id).snapshotChanges();
}
}
The log I get for console.log(this.item) is undefined. Calling this.item in the console returns the same. I am unsure of how to proceed and would appreciate any guidance. Logging res in the console returns a byzantine object. Perhaps that's how I access the item, but if so, why is it not saved in this.item and how do I access the item's values?
snapshotChanges returns an observable of actions, not the actual value.
You should extract the value with action.payload.doc.data():
So your code should look like the following example.
getItem(id) {
return this.firestore.collection('items').doc(id).snapshotChanges()
.pipe(
map(actions => actions.map(a => {
const data = a.payload.doc.data();
const id = a.payload.doc.id;
return { id, ...data };
})
);
}
Or you can use valueChanges of doc.
getItem(id) {
return this.firestore.collection('items').doc(id).valueChanges();
}

Shared service example Angular 5

I know this question has been asked several times, but problem is that nobody tried to make a some fiddle or show results of code. This is what i have, i need to update values in other component based on value in some other component, but that is not just value,I have call function again in some other component.
I have some component that goes to database and update values, on second hand I have other component that read those values from database from service.
This is example of my code
tasks.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import { environment } from '../../environments/environment';
import { Tasks } from './tasks';
#Injectable()
export class TasksProvider {
constructor(private http: HttpClient) { }
createNewTask(name: Name) : Observable<any> {
return this.http.post(environment.apiUri + 'tasks', { name, finished: false },
{ responseType: 'text' });
}
updateTask(id: Id, name: Name, finished: boolean) : Observable<any> {
return this.http.put(environment.apiUri + 'tasks/' + id, { name, finished },
{ responseType: 'text' });
}
getAllTasks(): Observable<Tasks[]> {
return this.http.get(environment.apiUri + 'tasks')
.map<any, Tasks[]>(data => data.map(Tasks.fromObject));
}
}
app.component.html
<app-tasks-list></app-tasks-list>
<app-tasks-add-new></app-tasks-add-new>
As you may see I have not child components, that is my main problem
tasks-list.component.ts
import {Component} from '#angular/core';
import { Tasks } from '../services/tasks';
import { TasksProvider } from '../services/tasks.service';
#Component({
selector: 'app-tasks-list',
templateUrl: './tasks-list.component.html',
styleUrls: ['./tasks-list.component.scss']
})
export class TasksListComponent {
tasks: Array<Tasks>;
constructor(private tasksProvider: TasksProvider) { }
ngOnInit() {
this.getTasksList();
}
displayedColumns: string[] = ['id', 'name', 'finished'];
private getTasksList() {
this.tasksProvider.getAllTasks()
.subscribe(tasks => {
this.tasks = tasks;
});
}
public updateCheckboxValue(id: number, name: string, event: any){
this.tasksProvider.updateTask(id, name, event.checked).subscribe(
result => {},
() => {
alert('Something went wrong');
})
}
}
tasks-add-new.component.ts
import { Component, OnInit, Inject } from '#angular/core';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '#angular/material';
import { Tasks } from '../services/tasks';
import { TasksProvider } from '../services/tasks.service';
export interface DialogData {
name: string;
}
#Component({
selector: 'app-tasks-add-new',
templateUrl: './tasks-add-new.component.html',
styleUrls: ['./tasks-add-new.component.scss']
})
export class TasksAddNewComponent implements OnInit {
ngOnInit() {
}
constructor(public dialog: MatDialog, private tasksProvider: TasksProvider) {}
openDialog(): void {
const dialogRef = this.dialog.open(TasksAddNewDialog, {
width: '250px',
data: {name: this.animal}
});
dialogRef.afterClosed().subscribe(result => {
this.name = result
this.tasksProvider.createNewTask(this.name).subscribe(
result => {},
() => {
alert('Something went wrong');
})
}
}
}
#Component({
selector: 'tasks-add-new-dialog',
templateUrl: 'tasks-add-new-dialog.html'
})
export class TasksAddNewDialog {
constructor(
public dialogRef: MatDialogRef<TasksAddNewDialog>,
#Inject(MAT_DIALOG_DATA) public data: DialogData) {}
onNoClick(): void {
this.dialogRef.close();
}
}
You see now when i call function in tasks-add-new.component.ts like
this.tasksProvider.createNewTask(this.name).subscribe(
result => {},
() => {
alert('Something went wrong');
})
I need to call again function in tasks-list.component.ts
private getTasksList() {
this.tasksProvider.getAllTasks()
.subscribe(tasks => {
this.tasks = tasks;
});
}
Does any body have idea how i can do that the best practice?
On of the possible approach is to use Subjects.
1) Store task list on the service and provide subscribable Subject
private tasks: Array<Task>;
public $tasks: BehaviorSubject<Array<Task>>;
constructor(private http: HttpClient) {
this.$tasks = new BehaviorSubject([]);
...
}
getAllTasks() {
this.http.get(environment.apiUri + 'tasks')
.subscribe(data => {
this.tasks = data;
this.$tasks.next(this.tasks);
});
}
updateTask(params) {
this.http.post(/* params */).subscribe((task) => {
this.tasks = this.tasks.map(t => t.id !== task.id ? t : task);
this.$tasks.next(this.tasks);
});
}
createTask(...) {
// again, do a request, update this.tasks and call $tasks.next
...
}
2) Make one service Subject subscription on the component instead of multiple service methods Observable listeners and update component's list automatically each time the service source has been changed
tasks: Array<Tasks>;
constructor(private tasksProvider: TasksProvider) {
this.tasksProvider.$tasks.subscribe(tasks => this.tasks = tasks);
}
ngOnInit() {
this.tasksProvider.getAllTasks();
}
public updateCheckboxValue(id: number, name: string, event: any){
this.tasksProvider.updateTask(id, name, event.checked);
}

Angular - map always returns undefined

I have an angular page which has a list of properties. Each property has a link to view the details of the property. I have a function which maps the property by id, however as a return I am always getting undefined (printed in console).
service.ts
getProperties(): Observable<IProperty[]>{
return this.http.get<IProperty>('http://localhost:3000/')
.do(data => this.properties.push(JSON.stringify(data)))
.catch(this.handleError);
}
getProperty(id:number): Observable<IProperty>{
return this.getProperties()
.map((properties: IProperty[])=> properties.find(p=>p.propertyId===id));
}
propertyDetail.component.ts
import { Component, OnInit } from '#angular/core';
import { IProperty } from './property';
import { ActivatedRoute, Router } from '#angular/router';
import { ApiService} from '../api/api.service';
import { PropertyGuardService } from './property-guard.service'
#Component
({
selector: 'propertyDetail',
templateUrl: './propertyDetail.component.html',
providers: [PropertyGuardService]
})
export class PropertyDetailComponent implements OnInit
{
pageTitle:string = "Property Details";
property: IProperty;
errorMessage: string ="";
constructor(private _route : ActivatedRoute,
private _router: Router,
private apiService: ApiService){
console.log(this._route.snapshot.paramMap.get('id'));
}
ngOnInit(){
const param = this._route.snapshot.paramMap.get('id');
if(param){
const id = +param;
this.getProperty(id);
console.log(this.getProperty(id));
}
}
getProperty(id:number)
{
this.apiService.getProperty(id).subscribe(
property => this.property = property,
error => this.errorMessage = <any>error);
}
onBack(): void
{
this._router.navigate(['/properties']);
}
}
You set one property using property => this.property = property by subscribe in the suitable time and now you can use this.property in the view like {{property?.id}}.
If you want to check Property whether being fetched properly or not on the console, you can use as follows:
getProperty(id:number){
this.apiService.getProperty(id).subscribe(
property => {
this.property = property,
console.log(property) // check property returned here
});
}

Angular 2 shared service to pass data to component-to-component

I am trying to pass the string value of this.title from my LandingPage.component to my ResultPage.component.
I retrieve the list.show value, and send it to my TitleService in like so in my:
landingpage.component.html
<ol>
<li (click)="selectShow(list.show)" [routerLink]="['/details', list.id]" *ngFor="let list of shows">{{list.show}}
</li>
</ol>
landingpage.component.ts
import { TitleService } from '../../services/title.service';
constructor(private TitleService: TitleService) {}
selectShow(show) {
this.TitleService.fetchTitle(show)
}
The above sends the list.show value to my:
title.service.ts
// this gives us the name of the clicked show, which we send to TitleResolver
#Injectable()
export class TitleService {
fetchTitle(title) {
console.log("title is " + title); // this outputs correctly
return title;
}
}
And here is how I manage the routing in my:
app-routing.module.ts
import { TitleService } from './services/title.service';
const routes: Routes = [
{ path: '', component: LandingPage },
{
path: 'details/:id', component: ResultPage
}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [TitleService]
})
My question
Once I receive the title.show value in my service component, I'm unsure how to then send it to my receiving component (resultpage.component)
How can I send my title value from my service to my ResultPage.component?
Make the title a public property of the service like this:
// this gives us the name of the clicked show, which we send to TitleResolver
#Injectable()
export class TitleService {
selectedTitle: string;
fetchTitle(title) {
console.log("title is " + title); // this outputs correctly
this.selectedTitle = title;
return title; // No need to return it.
}
}
Then any other component can inject this service and access this.titleService.selectedTitle
In title.service.ts you can declare a variable called title and have setter and getter:
title: string ="";
// replace fetchTitle with setTitle
// remember to change it in the component too
setTitle(title) {
this.title = title;
}
getTitle() {
return this.title;
}
Then, when ResultPage.component is initialized, call getTitle() from TitleService and set the result to a variable declared in the component.
Here's an example of sharing data via shared services.
Separation of concerns... Your landing page is used to select the list item and navigate to the result page. Let it do just that and only that. Let the ResultPage.component do the rest. Note: Other answers recommend storing the value of the last title in the TitleService. It's not a good idea to store state in a service. Then TitleService cannot be used as a generic way to get any title separate from your current navigation, without side effects.
Remove (click) event. Add 'show' as a QueryParam.
landingpage.component.html
<li [routerLink]="['/details', list.id]"
[queryParams]="{show: list.show}"
*ngFor="let list of shows">
{{list.show}}
</li>
Subscribe to router params and queryparams to get the id and show.
resultpage.component.ts
import { Component, OnInit, OnDestroy } from '#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { TitleService } from '../../services/title.service';
#Component({
...
})
export class ResultPageComponent implements OnInit, OnDestroy {
itemId: string;
show: string;
subParams: any; // infinite Observable to be unsubscribed
subQueryParams: any; // infinite Observable to be unsubscribed
constructor(
...
private TitleService: TitleService,
protected route: ActivatedRoute,
protected router: Router,
...
) {}
ngOnInit() {
this.subParams = this.route.params.subscribe(this.onParams);
this.subQueryParams = this.route.queryParams(this.onQueryParams);
}
ngOnDestroy() {
// Delete active subscribes on destroy
this.subParams.unsubscribe();
this.subQueryParams.unsubscribe();
}
onParams = (params: any) => {
this.itemId = params['id'];
}
onQueryParams = (data: any) => {
this.show = data.show;
if(this.show) {
this.TitleService.fetchTitle(this.show)
}
}

Angular 2 access parent routeparams from child component [duplicate]

How do I get the RouteParams from a parent component?
App.ts:
#Component({
...
})
#RouteConfig([
{path: '/', component: HomeComponent, as: 'Home'},
{path: '/:username/...', component: ParentComponent, as: 'Parent'}
])
export class HomeComponent {
...
}
And then, in the ParentComponent, I can easily get my username param and set the child routes.
Parent.ts:
#Component({
...
})
#RouteConfig([
{ path: '/child-1', component: ChildOneComponent, as: 'ChildOne' },
{ path: '/child-2', component: ChildTwoComponent, as: 'ChildTwo' }
])
export class ParentComponent {
public username: string;
constructor(
public params: RouteParams
) {
this.username = params.get('username');
}
...
}
But then, how can I get this same 'username' parameter in those child components? Doing the same trick as above, doesn't do it. Because those params are defined at the ProfileComponent or something??
#Component({
...
})
export class ChildOneComponent {
public username: string;
constructor(
public params: RouteParams
) {
this.username = params.get('username');
// returns null
}
...
}
UPDATE:
Now that Angular2 final was officially released, the correct way to do this is the following:
export class ChildComponent {
private sub: any;
private parentRouteId: number;
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.sub = this.route.parent.params.subscribe(params => {
this.parentRouteId = +params["id"];
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}
ORIGINAL:
Here is how i did it using the "#angular/router": "3.0.0-alpha.6" package:
export class ChildComponent {
private sub: any;
private parentRouteId: number;
constructor(
private router: Router,
private route: ActivatedRoute) {
}
ngOnInit() {
this.sub = this.router.routerState.parent(this.route).params.subscribe(params => {
this.parentRouteId = +params["id"];
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}
In this example the route has the following format: /parent/:id/child/:childid
export const routes: RouterConfig = [
{
path: '/parent/:id',
component: ParentComponent,
children: [
{ path: '/child/:childid', component: ChildComponent }]
}
];
You shouldn't try to use RouteParams in your ChildOneComponent.
Use RouteRegistry, instead!
#Component({
...
})
export class ChildOneComponent {
public username: string;
constructor(registry: RouteRegistry, location: Location) {
route_registry.recognize(location.path(), []).then((instruction) => {
console.log(instruction.component.params['username']);
})
}
...
}
UPDATE: As from this pull request (angular beta.9): https://github.com/angular/angular/pull/7163
You can now access to the current instruction without recognize(location.path(), []).
Example:
#Component({
...
})
export class ChildOneComponent {
public username: string;
constructor(_router: Router) {
let instruction = _router.currentInstruction();
this.username = instruction.component.params['username'];
}
...
}
I haven't tried it, yet
Further details here:
https://github.com/angular/angular/blob/master/CHANGELOG.md#200-beta9-2016-03-09
https://angular.io/docs/ts/latest/api/router/Router-class.html
UPDATE 2:
A small change as from angular 2.0.0.beta15:
Now currentInstruction is not a function anymore. Moreover, you have to load the root router. (thanks to #Lxrd-AJ for reporting)
#Component({
...
})
export class ChildOneComponent {
public username: string;
constructor(_router: Router) {
let instruction = _router.root.currentInstruction;
this.username = instruction.component.params['username'];
}
...
}
As mentioned by Günter Zöchbauer, I used the comment at https://github.com/angular/angular/issues/6204#issuecomment-173273143 to address my problem. I used the Injector class from angular2/core to fetch the routeparams of the parent. Turns out angular 2 does not handle deeply nested routes. Maybe they'll add that in the future.
constructor(private _issueService: IssueService,
private _injector: Injector) {}
getIssues() {
let id = this._injector.parent.parent.get(RouteParams).get('id');
this._issueService.getIssues(id).then(issues => this.issues = issues);
}
I found an ugly but working solution, by requesting the parent (precisely the 2nd ancestor) injector, and by getting the RouteParams from here.
Something like
#Component({
...
})
export class ChildOneComponent {
public username: string;
constructor(injector: Injector) {
let params = injector.parent.parent.get(RouteParams);
this.username = params.get('username');
}
}
RC5 + #angular/router": "3.0.0-rc.1 SOLUTION: It seems that this.router.routerState.queryParams has been deprecated. You can get the parent route params this way:
constructor(private activatedRoute: ActivatedRoute) {
}
this.activatedRoute.parent.params.subscribe(
(param: any) => {
let userId = param['userId'];
console.log(userId);
});
You can take component of parent route inside of child component from injector and then get any from child component. In you case like this
#Component({
...
})
export class ChildOneComponent {
public username: string;
constructor(
public params: RouteParams
private _injector: Injector
) {
var parentComponent = this._injector.get(ParentComponent)
this.username = parentComponent.username;
//or
this.username = parentComponent.params.get('username');
}
...
}
Passing Injector instance to constructor in child component may not be good if you want to write unit tests for your code.
The easiest way to work around this is to have a service class in the parent component, in which you save your required params.
#Component({
template: `<div><router-outlet></router-outlet></div>`,
directives: [RouterOutlet],
providers: [SomeServiceClass]
})
#RouteConfig([
{path: "/", name: "IssueList", component: IssueListComponent, useAsDefault: true}
])
class IssueMountComponent {
constructor(routeParams: RouteParams, someService: SomeServiceClass) {
someService.id = routeParams.get('id');
}
}
Then you just inject the same service to child components and access the params.
#Component({
template: `some template here`
})
class IssueListComponent implements OnInit {
issues: Issue[];
constructor(private someService: SomeServiceClass) {}
getIssues() {
let id = this.someService.id;
// do your magic here
}
ngOnInit() {
this.getIssues();
}
}
Note that you should scope such service to your parent component and its child components using "providers" in parent component decorator.
I recommend this article about DI and scopes in Angular 2: http://blog.thoughtram.io/angular/2015/08/20/host-and-visibility-in-angular-2-dependency-injection.html
In RC6, router 3.0.0-rc.2 (probably works in RC5 as well), you can take route params from the URL as a snapshot in case that params won't change, without observables with this one liner:
this.route.snapshot.parent.params['username'];
Don't forget to inject ActivatedRoute as follows:
constructor(private route: ActivatedRoute) {};
With RxJS's Observable.combineLatest, we can get something close to the idiomatic params handling:
import 'rxjs/add/operator/combineLatest';
import {Component} from '#angular/core';
import {ActivatedRoute, Params} from '#angular/router';
import {Observable} from 'rxjs/Observable';
#Component({ /* ... */ })
export class SomeChildComponent {
email: string;
id: string;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
Observable.combineLatest(this.route.params, this.route.parent.params)
.forEach((params: Params[]) => {
this.id = params[0]['id'];
this.email = params[1]['email'];
});
}
}
I ended up writing this kind of hack for Angular 2 rc.1
import { Router } from '#angular/router-deprecated';
import * as _ from 'lodash';
interface ParameterObject {
[key: string]: any[];
};
/**
* Traverse route.parent links until root router and check each level
* currentInstruction and group parameters to single object.
*
* e.g.
* {
* id: [314, 593],
* otherParam: [9]
* }
*/
export default function mergeRouteParams(router: Router): ParameterObject {
let mergedParameters: ParameterObject = {};
while (router) {
let currentInstruction = router.currentInstruction;
if (currentInstruction) {
let currentParams = currentInstruction.component.params;
_.each(currentParams, (value, key) => {
let valuesForKey = mergedParameters[key] || [];
valuesForKey.unshift(value);
mergedParameters[key] = valuesForKey;
});
}
router = router.parent;
}
return mergedParameters;
}
Now in view I collect parameters in view instead of reading RouteParams I just get them through router:
#Component({
...
})
export class ChildishComponent {
constructor(router: Router) {
let allParams = mergeRouteParams(router);
let parentRouteId = allParams['id'][0];
let childRouteId = allParams['id'][1];
let otherRandomParam = allParams.otherRandomParam[0];
}
...
}
In FINAL with little help of RXJS you can combine both maps (from child and parent):
(route) => Observable
.zip(route.params, route.parent.params)
.map(data => Object.assign({}, data[0], data[1]))
Other questions one might have:
Is it really a good idea to use above - because of coupling (couple child component with parent's param's - not on api level - hidden coupling),
Is it proper approach in term of RXJS (it would require hardcore RXJS user feedback ;)
You can do it on the snapshot with the following, but if it changes, your id property will not be updated.
This example also shows how you can subscribe to all ancestor parameter changes and look for the one you are interested in by merging all of the parameter observables. However, be careful with this method because there could be multiple ancestors that have the same parameter key/name.
import { Component } from '#angular/core';
import { ActivatedRoute, Params, ActivatedRouteSnapshot } from '#angular/router';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/observable/merge';
// This traverses the route, following ancestors, looking for the parameter.
function getParam(route: ActivatedRouteSnapshot, key: string): any {
if (route != null) {
let param = route.params[key];
if (param === undefined) {
return getParam(route.parent, key);
} else {
return param;
}
} else {
return undefined;
}
}
#Component({ /* ... */ })
export class SomeChildComponent {
id: string;
private _parameterSubscription: Subscription;
constructor(private route: ActivatedRoute) {
}
ngOnInit() {
// There is no need to do this if you subscribe to parameter changes like below.
this.id = getParam(this.route.snapshot, 'id');
let paramObservables: Observable<Params>[] =
this.route.pathFromRoot.map(route => route.params);
this._parametersSubscription =
Observable.merge(...paramObservables).subscribe((params: Params) => {
if ('id' in params) {
// If there are ancestor routes that have used
// the same parameter name, they will conflict!
this.id = params['id'];
}
});
}
ngOnDestroy() {
this._parameterSubscription.unsubscribe();
}
}
Getting RouteParams from parent component in Angular 8 -
I have a route http://localhost:4200/partner/student-profile/1234/info
Parent route - student-profile
Param - 1234 (student_id)
Child route - info
Accessing param in child route (info) -
Import
import { ActivatedRoute, Router, ParamMap } from '#angular/router';
Constructor
constructor(private activatedRoute: ActivatedRoute, private router: Router) { }
Accessing parent route params
this.activatedRoute.parent.paramMap.subscribe((params: ParamMap) => this.studentId = (params.get('student_id')));
Now, our variable studentId has the param value.

Categories