0

I am working on an angular application for work that needs to implement permissions. The permissions are currently stored in the backend as a 1 or a 0, and the front end calls a service to return the user's permission and if the user does not have permission for a certain action, the button to perform that action is disabled. We thought about it for a while and decided that the best option would be to save the permission to session storage on start up and get it from there whenever it needs to be checked.

This works very well after the application starts, every page successfully reads the permission and disabled the appropriate buttons, however I am having an issue with the initial start up of the application. The permission must be received through an asynchronous method, so the application continues startup while the permission is being received. Since the default is no permission, the first page has a button disabled even after the permission is received because it was created before the asynchronous method was called. After a refresh it works as intended.

I have been trying to find a way to either detect when the change is made to session storage and update the initial component accordingly or have the application wait for the method to get permissions to finish before continuing startup. Any help would be appreciated.

-Thanks

  • This is where rxjs can really help you. So don’t make it sync by storing it in sessionStorage, instead, next a behaviorSubject and async subscribe to it in your template (ideally through a directive). That way, it will update the view once the permissions come in. Another way might be to use a resolver on routes that have components with conditionals on there, so they are always available when the component loads. – MikeOne May 30 '22 at 17:30

2 Answers2

1

Try this, it works for me

Create a service called BroadCasterService -

import { Injectable } from '@angular/core';
import { Subject, Observable, BehaviorSubject } from 'rxjs';
import { filter, map } from 'rxjs/operators';

export class BroadcasterModel {
key: string=''
data: any;
}
@Injectable({
providedIn: 'root'
})
export class BroadCasterService {
public title = new BehaviorSubject('');
private subject = new Subject<BroadcasterModel>();
public sideNavToggleSubject: BehaviorSubject<any> = new 
BehaviorSubject(null);
broadcast(key:string, data:any) {
    this.subject.next({ key: key, data: data });
}
on(key:string): Observable<any> {
    return this.subject.pipe(filter(m => m.key == key), map(m => 
m.data));
}
setTitle(title: string) {
    this.title.next(title);
}
public toggle(data:any) {
    return this.sideNavToggleSubject.next(data);
  } 
}

Then import this service in your component where you set your session data -

import { BroadCasterService } from '../services/broad-caster.service';

Add services in constructor -

 constructor(private broadcastService: BroadCasterService)

Then along with the session data, set the permission data in broadcast as well -

this.sharedService.getPermission('').subscribe((res: any) => {
  this.storage.setLocalStorageData('permissionData', res?.data, true);
  this.broadcastService.broadcast("permissionData", res?.data);
});

Call broadcast service where you set permissions -

let modules :any;
 modules = localStorage.getItem("permissionData");
 this.broadcastService.on('permissionData').subscribe(cic => {
        modules = cic; //this keeps the data until the page is refresh
 });

After refresh the page you get the permission data from session storage.

I hope it will be helpful for you.

  • The button already updates after a refresh, my issue is that the http get is too slow to be completed before the application needs to check permission, so when it starts up the button is disabled. If this will update the button automatically after local storage is changed then it does fix the issue, but I am a little bit confused by the wording. Thank you. – William White May 31 '22 at 16:56
  • As I see your component is loading first and your API response is coming later. because of which you don't get the permission when your html is render. Am I right ? – kavita singhal May 31 '22 at 19:09
  • if yes, then defiantly it will be solve your problem. If you ever subscribes to Behavior subject, it is going to instantly receive whatever the most recent value was. The behavior subject is always going to have some value to give out to a subscriber. So I have used Behavior Subject to solve this problem. In this way, after getting API response, you will get the permission data when you subscribes to Behavior subject. do you understand now ? – kavita singhal May 31 '22 at 19:09
  • I do, I'll try implementing it now> Thanks! – William White May 31 '22 at 19:46
  • In your code you have something called BroadcasterModel, I am not sure what that would be. Is it the object being returned from the async function? – William White May 31 '22 at 19:53
  • Check my edited answer. This is a class which I have made in BroadCasterService. – kavita singhal May 31 '22 at 20:53
  • Great ! If that work please vote up so it can help others as well. – kavita singhal Jun 01 '22 at 18:13
0

Hi I prepared a dummy process-diagram: https://lucid.app/lucidchart/758acc33-e7b9-41b0-b106-27fcfb6604eb/edit?invitationId=inv_01cefa4e-73cc-4ef0-88d9-7187f0ac1559#

Process Diagram

You have some options to implement something like that.

  1. HttpInterceptors + UI-Spinner during all backend requests. Tutorials: Angular show spinner for every HTTP request with very less code changes https://indepth.dev/tutorials/angular/how-to-implement-global-loaders-using-http-interceptors
  2. Custom solution, which covers only this case ( without HttpInterceptor )
  3. Using resolvers
DeanTwit
  • 325
  • 4
  • 8