Reputation: 3
Im working with an angular application which has a sidebar component. Depending on the role of the user signed in, there will be more options on the sidebar. For example, a superadmin will have an additional dashboard for him.
The issue is the role is being stored in local storage in the app component's ts while it is being retrived in the nav component ngAfterViewInit. But the code in ngAfterViewInit is being executed first such that it gets a null role.
Here is a code snippet:
App.component.ts
constructor
(private auth: AuthService)
ngOnInit(){
this.auth.
authenticate.subscribe(res
=>{ this.storageService.
set('userRole', res.role) })
nav.component.ts
ngAfterViewInit(){
this.role = this.
storageService.
get('userRole')
storageservice.ts
get(key: string){
const keyVal = string | null =
localStorage.getItem(key)
if(stringValue){
return JSON.parse(keyVal);
}
}
The value returned is null. I logged it in console n saw that retrieving the value was executed before setting it.
Getting this error:
main.50d4493a21037afa5155.js:1
ERROR TypeError: Cannot read properties of undefined (reading '0')
at t._next (main.50d4493a21037afa5155.js:1:2189226)
at t.__tryOrUnsub (main.50d4493a21037afa5155.js:1:544147)
at t.next (main.50d4493a21037afa5155.js:1:543316)
at t._next (main.50d4493a21037afa5155.js:1:542366)
at t.next (main.50d4493a21037afa5155.js:1:542037)
at t._next (main.50d4493a21037afa5155.js:1:551777)
at t.next (main.50d4493a21037afa5155.js:1:542037)
at t._subscribe (main.50d4493a21037afa5155.js:1:1526055)
at e._trySubscribe (main.50d4493a21037afa5155.js:1:545724)
at t._trySubscribe (main.50d4493a21037afa5155.js:1:548182)
Im doing a check as posted for role in nav component then assign it to a variable
Upvotes: 0
Views: 1077
Reputation: 8558
What you can do is to create a BehaviorSubject
in the StorageService
that the components/services can subscribe to and get the latest stored value.
Upon each set
call, you can update the BehaviorSubject
with the latest value, and all the subscribers will be called. You can use map()
pipeable operator to filter by key.
And of course, you need to populate the subject on service startup:
export class StorageService{
private currentStorage = new BehaviorSubject({});
constructor() {
this.updateSubject()
}
set(key: string, value: any){
localStorage.setItem(key, value);
this.updateSubject();
}
updateSubject(){
this.currentStorage.next({...localStorage})
}
get(key: string){
return localStorage.getItem(key)
}
watch(key: string){
return this.currentStorage.pipe(
map(items => items[key])
)
}
}
In the app.component
, you can set the value like before:
ngOnInit(){
this.auth.authenticate.subscribe(res =>{ this.storageService.
set('userRole', res.role) }
)
}
And in the nav.component
, you can subscribe to it like this:
ngAfterViewInit(){
this.storageService.watch('userRole').subscribe(role => this.role = role)
}
You can find a working example here: https://stackblitz.com/edit/angular-ivy-ffp2qi?file=src/app/storage.service.ts
Upvotes: 1