In one of my Angular 2 routes\'s templates (FirstComponent) I have a button
first.component.html
3rd approach is most common way to share data between components. you may inject the item service which you want to use in related component.
import { Injectable } from '@angular/core';
import { Predicate } from '../interfaces'
import * as _ from 'lodash';
@Injectable()
export class ItemsService {
constructor() { }
removeItemFromArray<T>(array: Array<T>, item: any) {
_.remove(array, function (current) {
//console.log(current);
return JSON.stringify(current) === JSON.stringify(item);
});
}
removeItems<T>(array: Array<T>, predicate: Predicate<T>) {
_.remove(array, predicate);
}
setItem<T>(array: Array<T>, predicate: Predicate<T>, item: T) {
var _oldItem = _.find(array, predicate);
if(_oldItem){
var index = _.indexOf(array, _oldItem);
array.splice(index, 1, item);
} else {
array.push(item);
}
}
addItemToStart<T>(array: Array<T>, item: any) {
array.splice(0, 0, item);
}
getPropertyValues<T, R>(array: Array<T>, property : string) : R
{
var result = _.map(array, property);
return <R><any>result;
}
getSerialized<T>(arg: any): T {
return <T>JSON.parse(JSON.stringify(arg));
}
}
export interface Predicate<T> {
(item: T): boolean
}
I think since we don't have $rootScope kind of thing in angular 2 as in angular 1.x. We can use angular 2 shared service/class while in ngOnDestroy pass data to service and after routing take the data from the service in ngOnInit function:
Here I am using DataService to share hero object:
import { Hero } from './hero';
export class DataService {
public hero: Hero;
}
Pass object from first page component:
ngOnDestroy() {
this.dataService.hero = this.hero;
}
Take object from second page component:
ngOnInit() {
this.hero = this.dataService.hero;
}
Here is an example: plunker
By default i won't use a guard for this one for me it is more can i enter the route or can i leave it. It is not to share data betweenn them.
If you want to load data before we entered a route just add an resolver to this one this is also part of the Router.
As very basic example:
Resolver
import { Resolve, ActivatedRoute } from "@angular/router";
import { Observable } from "rxjs";
import { Injectable } from "@angular/core";
import { take } from "rxjs/operators";
@Injectable()
export class UserResolver implements Resolve<User> {
constructor(
private userService: UserService,
private route: ActivatedRoute
) {}
resolve(): Observable<firebase.User> {
return this.route.params.pipe(
switchMap((params) => this.userService.fetchUser(params.user_id)),
take(1)
);
}
}
put to the router:
RouterModule.forChild([
{
path: "user/:user_id",
component: MyUserDetailPage,
resolve: {
user: UserResolver
}
}
}]
get the data in our component
ngOnInit() {
const user: firebase.User = this.activatedRoute.snapshot.data.user;
}
The downside on this approach is, he will enter the route first if he get the user data not before, this ensures the data for the user has been loaded and is ready on start of the component, but you will stay on the old page as long the data has been loaded (Loading Animation)
It is 2019 and many of the answers here would work, depending on what you want to do. If you want to pass in some internal state not visible in URL (params, query) you can use state
since 7.2 (as I have learned just today :) ).
From the blog (credits Tomasz Kula) - you navigate to route....
...from ts: this.router.navigateByUrl('/details', { state: { hello: 'world' } });
...from HTML template: <a routerLink="/details" [state]="{ hello: 'world' }">Go</a>
And to pick it up in the target component:
constructor(public activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.state$ = this.activatedRoute.paramMap
.pipe(map(() => window.history.state))
}
Late, but hope this helps someone with recent Angular.
I looked at every solution (and tried a few) from this page but I was not convinced that we have to kind of implement a hack-ish way to achieve the data transfer between route.
Another problem with simple history.state
is that if you are passing an instance of a particular class in the state
object, it will not be the instance while receiving it. But it will be a plain simple JavaScript object.
So in my Angular v10 (Ionic v5) application, I did this-
this.router.navigateByUrl('/authenticate/username', {
state: {user: new User(), foo: 'bar'}
});
And in the navigating component ('/authenticate/username'
), in ngOnInit()
method, I printed the data with this.router.getCurrentNavigation().extras.state
-
ngOnInit() {
console.log('>>authenticate-username:41:',
this.router.getCurrentNavigation().extras.state);
}
And I got the desired data which was passed-
Some super smart person (tmburnell) that is not me suggests re-writing the route data:
let route = this.router.config.find(r => r.path === '/path');
route.data = { entity: 'entity' };
this.router.navigateByUrl('/path');
As seen here in the comments.
I hope someone will find this useful