angular2 - Pass value from parent route to child route - javascript

I have a route called home and it has three child routes, documents, mail and trash. In the home route component it has a variable called 'user'. I know there are a few ways of passing info between parent and child components highlighted here, but how am I suppose to pass info between parent/child routes.
{ path: 'home', component: HomeComponent, children: [
{ path: 'documents', component: DocumentsComponent },
{ path: 'mail', component: MailComponent },
{ path: 'trash', component: TrashComponent },
]
},
Service
import { Injectable } from '#angular/core';
#Injectable()
export class HomeService {
// Mock user, for testing
myUser = {name:"John", loggedIn:true};
// Is Super Admin
isLogged():boolean {
if(this.myUser.role == true){
return true ;
}
return false ;
}
}
Component
constructor(public router: Router, public http: Http, private homeService: HomeService) {
}
isLogged(){
return this.homeService.isLogged();
}
Template
<div class="side-nav fixed" >
<li style="list-style: none">
<img alt="avatar" class="circle valign profile-image" height="64" src=
"../images/avatar.jpg" width="64">
<div class="right profile-name">
<!-- Value not changing even with service -->
{{myUser.role}}
</div>
</li>

You may use a common service to pass data like explained in the Angular Documentation
Basically you may create a Service which will have a user object, which can be updated once your parent route gets loaded or with some action on parent component.
UserService
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs/Subject';
#Injectable()
export class UserService {
// Observable user
user = new Subject<string>();
}
And then when the child route component gets loaded you may retrieve the value from the Service.
HomeComponent
#Component({
...
})
export class HomeComponent{
...
constructor(private userService:UserService ){}
someMethod = () =>{
this.userService.user.next(<pass user object>);
}
}
MailComponent
#Component({
...
})
export class HomeComponent{
...
constructor(private userService:UserService ){
this.userService.user.subscribe(userChanged);
}
userChanged = (user) => {
// Do stuff with user
}
}
Service object will be same instance in child if you add the provider in the parent.

Check out :- https://angular.io/docs/ts/latest/guide/router.html#!#link-parameters-array
You can pass data while changing routes on click as :-
<a [routerLink]="['/crisis-center', { foo: myVar }]">Crisis Center</a>

Related

How to change the header on parent component according to route

Using Angular 7.x, I want to change my parent header component accordingly to the child routes and if they're activated or not. So in my case
AppComponent
Feature Module <= detect changes here
Child Components of feature module
So my routing is very simple, the app-routing.module just contains the loading of the feature module with loadChildren, nothing fancy here.
Then this feature module contains the routes for the child components. There is one parentComponent, we call it ParentComponent which contains the router-outlet. There is also some headers that I want to change accordingly to the childs.
SO i have two child components: create, and ':id' (detail page). When I trigger these routes I need the parent component to just change their text content accordingly. So for example when the create page is triggered I want to add the header: "Create new item", and for the :id page I want to show "Detail page".
Now, I have figured out I need to subscribe to the router events or on the activatedRoute (or snapshot). I'm at a loss here so I don't really know what to do here.
My parent component looks like this now:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
#Component({
selector: 'parent-component',
templateUrl: './parent.component.html',
})
export class ParentComponent implements OnInit {
title = 'Parent Title';
// Check if it is possible to change the title according to the route
subtitle = 'Parent subtitle';
constructor(private readonly router: Router, private readonly route: ActivatedRoute) {}
ngOnInit(): void {
this.route.url.subscribe(data => {
if (this.route.snapshot.firstChild) {
console.log('yes', this.route.snapshot.firstChild);
// Change header with a if/else or switch case here
} else {
// Display standard text
console.log('no');
}
});
}
}
this is the output of the console.logs, notice in my real application the parent is named 'timesheets'.
Is there maybe another solution for this? Maybe a service, but all of the information is basically in the route already, so I'm trying to figure out if this is the way to go for my problem.
You can listen NavigationEnd events in ParentComponent or (I think) even better you can use a title service.
Solution 1:
In ParentComponent
import {NavigationEnd, Router} from '#angular/router';
import {filter} from 'rxjs/operators';
...
constructor(private router: Router, private readonly route: ActivatedRoute) {
this.subscribeRouterEvents();
}
subscribeRouterEvents = () => {
this.router.events.pipe(
filter(e => e instanceof NavigationEnd)
).subscribe(() => {
this.title = this.route.snapshot.data['title'];
// Assuming your route is like:
// {path: 'path', component: MyComponent, data: { title: 'Page Title'}}
});
Solution 2:
Using TitleService. Create a service that holds the page title, subscribe to title from ParentComponent and send new title to service from ChildComponent.
TitleService
#Injectable({
providedIn: 'root'
})
export class TitleService {
private defaultTitle = 'Page Title';
private titleSubject: BehaviorSubject<string> = new BehaviorSubject(this.defaultTitle);
public title: Observable<string>;
constructor(private titleService: Title) {
this.title = this.titleSubject.asObservable();
}
public setTitle(title: string) {
this.titleSubject.next(title);
}
}
ParentComponent
pageTitle = 'Page Title';
constructor(private titleService: TitleService) {}
ngOnInit(){
this.titleService.title.subscribe(value => this.pageTitle = value);
}
ChildComponent
pageTitle = 'Child Component Title';
constructor(private titleService: TitleService) {}
ngOnInit(){
this.titleService.setTitle(this.pageTitle);
}
You can try setting the title for a child as part of route like this.
const routes: Routes =[
{
path: 'create',
component: SomeComponent,
data : {header_title : 'some title'}
},
];
ngOnInit() {
this.title = this.route.data.subscribe(x => console.log(x));
}
and get the title in the child component and set that as header title using a service.

Navigate in Angular 7 without adding parameter to URL

I want to navigate between two routes in Angular 7 with posting data between them. But I don;t want to show those parameter in URL. How to do it in proper way?
at this moment I am strugging with something like this:
this.router.navigate(['/my-new-route', {data1: 'test', test2: 2323, test: 'AAAAAAA'}]);
and it change my url to
http://localhost:4200/my-new-route;data1=test;test2=2323;test=AAAAAAA
how to do it to cancel those data from url:
http://localhost:4200/my-new-route
Edit:
My case:
/form - route with some form
/options - route with some data
on /form route - users have some form with empty fields to fill manually
but on /options page there is some preset configuration, when user choose one is navigated to /form and fields are fill autmatically
when they move back to another page and back again to /form - should see empty form. Only link from /options to /form should fill those fields.
You can create a service and share it between both the components (the one that you're moving from, and the one that you're moving to).
Declare all the parameters that you want to pass to the URL, in the service, and before the router.navigate([]), set the values for parameters in the service.
You can access those parameters from the other component with that service.
Example:
SharedService
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class SharedService {
data1;
test2;
test;
}
Component1
import { SharedService } from 'location';
import { Router } from '#angular/router';
...
constructor(private _sharedService: SharedService,
private _router: Router) { }
...
this._sharedService.data1 = 'test'
this._sharedService.test2 = 2323;
this._sharedService.test = 'AAAAAAAA';
this._router.navigate(['/my-new-route']);
...
Component2
import { SharedService } from 'location';
...
private test2;
private test;
private data1;
constructor(private _sharedService: SharedService){ }
ngOnInit() {
this.data1 = this._sharedService.data1;
this.test2 = this._sharedService.test2;
this.test = this._sharedService.test;
...
}
There are few ways to do it.
Try 1 :
this.router.navigate(['/some-url'], { queryParams: filter, skipLocationChange: true});
Try 2 :
We can use this work around instead by using EventEmitter and BehaviorSubject with a shared service
In component 1:
this.router.navigate(['url']).then(()=>
this.service.emmiter.emit(data)
)
In service :
emmiter : EventEmitter = new EventEmitter();
In component 2: inside constructor
this.service.emmiter.subscribe();
another solution for passing information from one route to another without touching the query params is via the state field of NavigationExtras (as of Angular 7.2+)
something along these lines
// Publish
<a
[routerLink]="['/studies', study.id]"
[state]="{ highlight: true }">
{{study.title}}
</a>
// Subscribe
constructor(private route: ActivatedRoute, ...) {
}
public highlight: boolean;
public ngOnInit() {
...
this.route.paramMap
.pipe(map(() => window.history.state))
.subscribe(state => {
this.highlight = state && state.highlight;
});
...
}
// Alternative
constructor(private router: Router, ...) {
}
public highlight: boolean;
public ngOnInit() {
...
this.router.events.pipe(
filter(e => e instanceof NavigationStart),
map(() => this.router.getCurrentNavigation().extras.state)
)
.subscribe(state => {
this.highlight = state && state.highlight;
})
...
}
pass value through "state" key from which you want to naviagte to next component:
//From where we Navigate
import {ActivatedRoute, NavigationExtras, Router} from "#angular/router";
export class MainPageComponent {
constructor(public router:Router) {}
navWithExtraValue () {
const navigationExtras: NavigationExtras = {
state: {
editMode: true
},
};
}
}
//In constructor where we Navigated
constructor(public router:Router,
public route:ActivatedRoute){
this.route.queryParams.subscribe(data=> {
if (this.router.getCurrentNavigation().extras.state) {
this.editMode = this.router.getCurrentNavigation().extras.state.editMode;
}
});
We don't see these value in url

Angular 6 - navigation to child route refreshes whole page

So I'm using Angular 6 and I'm trying to navigate to a child route from the parent route. The navigation is successful, however there is an unwanted page refresh upon rendering the child component. In other words, the navigation works but it also refreshes the page for no apparent reason. Here is my code:
const appRoutes: Routes = [
{
path: "parent/:param1/:param2", component: ParentComponent,
children: [
{ path: ":param3", component: ChildComponent }
]
},
{ path: "", redirectTo: "/index", pathMatch: "full" },
{ path: "**", redirectTo: "/index" }
];
My parent component looks like this:
import { Component } from "#angular/core";
import { ActivatedRoute } from "#angular/router";
#Component({
selector: "my-parent",
templateUrl: "./parent.component.html"
})
export class ParentComponent {
param1: string;
param2: string;
loading: boolean;
tutorials: any[];
constructor(public route: ActivatedRoute) {
this.loading = true;
this.param1= this.route.snapshot.params.param1;
this.param2 = this.route.snapshot.params.param2;
// get data here
}
}
And my child component looks like this:
import { Component } from "#angular/core";
import { ActivatedRoute } from "#angular/router";
#Component({
selector: "my-child",
templateUrl: "./child.component.html"
})
export class ChildComponent {
param1: string;
param2: string;
param3: string;
loading: boolean;
result: any;
constructor(public route: ActivatedRoute) {
this.loading = true;
this.param1= this.route.snapshot.params.param1;
this.param2 = this.route.snapshot.params.param2;
this.param3 = this.route.snapshot.params.param3;
}
}
Now, the way I try to navigate from the parent component to the child component is the following one:
<a [routerLink]="['/parent', param1, param2, param3]">
<b>Navigate</b>
</a>
As I've said, the navigation is successful, but there is an unwanted page refresh which I want to get rid of and I haven't been able to find a working solution. I don't really know what's causing it. I am new to Angular 6.
Thanks in advance for your answers.
EDIT: added parent component html
<router-outlet></router-outlet>
<div class="row" *ngIf="route.children.length === 0">
// content here
</div>
So I found a working solution, which while not very elegant, it... works. In my parent component I created a method like this one:
constructor(public route: ActivatedRoute, private router: Router) {
this.loading = true;
this.param1 = this.route.snapshot.params.param1;
this.param2 = this.route.snapshot.params.param2;
// get data
}
navigateToChild(param3: string) {
this.router.navigate([param3], { relativeTo: this.route });
}
And in the parent template, I did this:
<a (click)="navigateToChild(paramFromServer)">
<b>Navigate</b>
</a>
No more refreshes for this one.
Thank you for your help everyone.
Remove the leading / from [routerLink]= "['/parent'...]" url. The / is telling the app to find the component route from the root of the application whereas no leading / will try to redirect to the child relative to the current component.
Also make sure you have added a <router-outlet> to the parent.component.html as that is where the child component will first try to be added on navigate. If that is not available it might be causing a full refresh to load in the new component from scratch.
const appRoutes: Routes = [
{
path: "parent/:param1/:param2", component: ParentComponent,
children: [
{ path: ":param3", component: ChildComponent }
]
},
// remove this 2 lines
// redirect to index thing is not needed
];
You didn't define param3 in your ParentComponent. Also you may need to change the strategy of params so your ChildComponent can retrieve the params from its parent.
Please check this stackblitz:
https://stackblitz.com/edit/angular-tvhgqu
In my case 'href' was the problem. Using routerLink solved the problem.
Problematic Approach:
<a href='/dashboard/user-details'>User</a>
Solution:
<a routerLink='/dashboard/user-details'>User</a>

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)
}
}

Why is my user ID undefined when passing it into my URL?

I am building a profile page and trying to get the authenticated user data to display there. My API call works with their id, and it works on the front end if I manually enter the id into the url.
But when I try to navigate to the profile from the navbar, I receive a
400 Bad Request for URL: http://localhost:3000/users/undefined
What I can assume right now is that it's an asynchrony issue. My profile page calls the user data, but that user data isn't available in my nav component. And it seems as though I need to pass in my id param into my profile [routerLink] if I want to navigate correctly. Since my user data isn't available in my nav component, it has nothing to pass.
Is there a better approach to this? Should I be using an event emitter?
Fairly new to Angular - help much appreciated!
Profile Component
import { Component, OnInit, Input } from '#angular/core';
import { AuthService } from '.././services/auth.service';
import { UserService } from '.././services/user.service'
import { Router, ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css'],
providers: [UserService]
})
export class ProfileComponent implements OnInit {
currentUser;
isAuth: boolean;
constructor(
private session: AuthService,
private router: Router,
private userService: UserService,
private route: ActivatedRoute
) {
this.session.isAuth
.subscribe((isAuth: boolean) => {
// user will be false if logged out
// or user object if logged in.
this.isAuth = isAuth;
});
if (this.session.token) {
this.isAuth = true;
console.log(this.session);
} else {
this.isAuth = false;
}
}
ngOnInit() {
this.route.params.subscribe(params => {
this.getUserDetails(params['id']);
});
}
getUserDetails(id) {
this.userService.get(id)
.subscribe((user) => {
this.currentUser = user;
console.log(this.currentUser);
});
}
}
Nav Template
Where I'm navigating to my profile page.
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">bnb</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li *ngIf="!isAuth"><a [routerLink]="['login']">Login</a></li>
<li *ngIf="isAuth"><a [routerLink]="['profile']"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Profile</a></li>
<li *ngIf="isAuth"><a (click)="logout()">Logout</a></li>
<li *ngIf="!isAuth"><a [routerLink]="['signup']">Signup</a></li>
</ul>
</div>
</div>
</nav>
Nav Component
import { Component, OnInit, Input } from '#angular/core';
import { AuthService } from '.././services/auth.service';
import { UserService } from '.././services/user.service';
import { Router, ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
isAuth: boolean;
currentUser: any;
constructor(
private session: AuthService,
private userService: UserService,
private router: Router,
private route: ActivatedRoute
) {
this.currentUser = JSON.parse(localStorage.getItem("User"))
console.log("USER",this.currentUser) //Currently returns Null
console.log(this.session)
this.session.isAuth
.subscribe((isAuth: boolean) => {
// user will be false if logged out
// or user object if logged in.
this.isAuth = isAuth;
});
if (this.session.token) {
this.isAuth = true;
} else {
this.isAuth = false;
}
}
ngOnInit() {
}
logout() {
this.session.logout();
}
}
Router
import { Routes } from '#angular/router';
import { LoginComponent } from '../login/login.component';
import { SignupComponent } from '../signup/signup.component';
import { HomeComponent } from '../home/home.component';
import { RentalListingsComponent } from '../rental-listings/rental-listings.component';
import { SingleRentalComponent } from '../rental-listings/single-rental/single-rental.component';
import { ProfileComponent } from '../profile/profile.component'
import { AuthService } from '../services/auth.service';
export const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path: 'signup', component: SignupComponent },
{ path: 'rentals', component: RentalListingsComponent },
{ path: 'listing', component: SingleRentalComponent },
{ path: 'profile/:id', component: ProfileComponent, canActivate: [AuthService] } <--profile path. I know I have to match my url paths, but don't know how to do this from the navbar.
// { path: 'home', component: HomeComponent, canActivate: [AuthService] },
{ path: '**', redirectTo: '' }
];
Thanks for providing the detail. Somewhere you need to subscribe to 'after login' or 'authentication' event, grab the user profile JSON, and save it to localstorage so you can use it anywhere you want. If you can't hook in or subscribe to one of these, then do it imperatively somewhere convenient in your code. Find out what call you can make to fetch the entire user JSON and save it as follows...
Check out my AuthService init() below. First line is this.authProvider.on('authenticated', this.onAuth);. Whatever authentication service API you are using should provide a way for you to specify a callback (providing the login token) whenever someone logs in. The onAuth callback function saves the token in localstorage and then fetchProfile(...){...} makes another call to the authentication service API to get the whole JSON user profile using the token just received this.user.getProfile(idToken, this.onProfile);. For example, I use Auth0 in projects, and my call to Auth0 API looks like this.lock.getProfile(idToken, this.onProfile); but I replaced that with an example of what your call might look like this.user.getProfile(idToken, this.onProfile); So use whatever your API uses replace in fetchProfile. Then the onProfile callback saves the entire JSON profile in a single key in local storage using this.localStorage.set('profile', profile); Then you can get it any time by calling this.localStorage.get('profile').
Do not provide UserService through the lazy-loaded ProfileComponent. That creates a separate branch on the dependency injection tree you might not want. See https://angular-2-training-book.rangle.io/handout/modules/shared-modules-di.html Import the UserService in a top-level module like AppModule or SharedModule and provide it there. No need to export it if it's in AppModule.
app.module.ts
...
#NgModule({
imports: [
...
UserService,
...
]
providers: [
...
UserService,
...
]
Handle Auth related stuff in Auth, not Profile. Profile seems visual/implementation-specific (e.g. it has a template). Here is a code snippet example.
auth.service.ts
#Injectable()
export class Auth {
userProfile: UserProfile;
constructor(
...
private localStorage: LocalStorageService,
private router: Router,
private user: UserService,
private authProvider: ...
...
) {
}
init() {
this.authProvider.on('authenticated', this.onAuth);
// Set userProfile attribute if already saved profile
this.userProfile = this.localStorage.get('profile');
setTimeout(() => { // let AppComponent listener initialize
this.localStorage.set('profile', this.userProfile);
}, 0);
}
}
onAuth = (authResult: AuthResult) => {
this.localStorage.set('id_token', authResult.idToken);
this.fetchProfile(authResult.idToken);
}
// Save current route for redirect url
login() {
this.localStorage.set('redirect_url', this.router.url);
this.authProvider.show({initialScreen: 'login'});
};
// Check if user is logged in.
authenticated() {
// Check if unexpired token.
// Searches for item in localStorage with key == 'id_token'
return this.authProvider.tokenNotExpired();
};
logout() {
this.router.navigateByUrl('');
this.userProfile = undefined; // do before localstorage
this.localStorage.remove('id_token');
this.localStorage.remove('profile');
};
fetchProfile(idToken: string) {
this.user.getProfile(idToken, this.onProfile);
}
/**
* On profile event callback.
* Save profile to LocalStorage.
* Redirect to url if present in LocalStorage.
*/
onProfile = (error: any, profile: UserProfile) => {
if (error) {
console.log(error);
return;
}
this.userProfile = profile;
this.localStorage.set('profile', profile);
// Redirect if there is a saved url to do so.
const redirectUrl: string = this.localStorage.get('redirect_url');
if (redirectUrl !== undefined) {
this.router.navigateByUrl(redirectUrl);
this.localStorage.remove('redirect_url');
}
}
Interact with localStorage through a LocalStorageService and subscribe to changes as follows.
localstorage.service.ts
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs/Subject';
#Injectable()
export class LocalStorageService {
[key:string]: any;
/**
* define your localstorage variables here as observables
*/
id_token$ = new Subject();
redirect_url$ = new Subject();
profile$ = new Subject();
customer$ = new Subject();
set(key: string, value: any) {
this[key + '$'].next(value); // this will make sure to tell every subscriber about the change.
localStorage.setItem(key, JSON.stringify(value));
}
get(key: string) {
const value = localStorage.getItem(key);
return value && JSON.parse(value);
}
remove(key: string) {
this[key + '$'].next(undefined);
localStorage.removeItem(key);
}
}
Don't do so much in constructor. Example:
app.component.ts
export class AppComponent implements OnDestroy, OnInit {
webRobot: boolean = false;
private profileSub: any;
private customerSub: any;
private subscriptionSub: any;
constructor(
private analyticsService: AnalyticsService,
private auth: Auth,
private localStorage: LocalStorageService,
) {
}
ngOnInit(): void {
this.init();
}
init() {
this.auth.init(this.webRobot);
this.analytics.init(this.webRobot);
if (!this.webRobot) {
// subscribe to authed profile changes
this.profileSub =
this.localStorage.profile$.subscribe(this.onProfile);
// Subscribe to changes to Stripe customer
this.customerSub =
this.localStorage.customer$.subscribe(this.onCustomer);
}
// always delete active subscribes on destroy
ngOnDestroy() {
this.profileSub.unsubscribe();
this.customerSub.unsubscribe();
}
onProfile = (profile: UserProfile) => {
// ...do stuff
}
onCustomer= (profile: Customer) => {
// ...do stuff
}
In your profile route configuration, it is expecting the id query param
{ path: 'profile/:id', component: ProfileComponent, canActivate: [AuthService] }
<--profile path.
I know I have to match my url paths,
but don't know how to do this from the navbar.
but your navbar link is not passing the id value
<li *ngIf="isAuth"><a [routerLink]="['profile']"><span class="glyphic
you need to do something like this in your navbar
<li *ngIf="isAuth"><a [routerLink]="['profile/user.id']">

Categories