Inquiry regarding Angular guard implementation using Observables

Looking for some clarity and knowledge as I navigate through this code.

I have an AuthService that checks the values in the localStorage for a specific key. This observable then uses .next to send the value back. In the Guard component, I reference this service and everything seems to be working fine. However, I've noticed that there is no redirect to the login page in the guard, so when authorization fails, the page just goes blank.

Below is the code snippet:

isLoggedIn(): Observable<boolean> {
  return new Observable((o) => {
    try {
      const cda = JSON.parse(localStorage.getItem('cda'));
      if (cda && cda.token) {
        console.log('Yes logged in');
        o.next(true);
      } else {
        console.log('Not logged in');
        o.next(false);
      }
    } catch (e) {
      console.log('Catch - Not logged in');
      o.next(false);
    }
  });
}
export class GuardGuard implements CanActivate {
  constructor(
    public auth: AuthService,
    public router: Router,
  ) { }

  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    return this.auth.isLoggedIn();
  }
}

How can I convert the Observable from the AuthService so that I can implement something like this:

if (!isLoggedIn) {
   this.router.navigateByUrl('/login');
}

Answer №1

To see a demonstration, follow this StackBlitz Link

**

MODIFY [ If you prefer not to use a third variable ]

service.ts

@Injectable()
export class DataService {
   constructor() { }
   isLoggedIn(): Observable<boolean> {
     return new Observable((o) => {
        try {
           const cda = JSON.parse(localStorage.getItem('cda'));
           if (cda && cda.token) {
              console.log('Yes logged in');
              o.next(true);
           } else {
             console.log('Not logged in');
             o.next(false);
           }
       } catch (e) {
         console.log('Catch - Not logged in');
         o.next(false);
     }
   });  
 }
}

your-guard.ts

export class RouterGuard implements CanActivate {
constructor(private dService : DataService,
          private router: Router){}
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
       return this.dService.isLoggedIn().pipe(
        map(value =>  {
          if(!value) this.router.navigate(['/login'])
          return value;
        })
      )
    }
}

**

---- MODIFICATION COMPLETE ----

In your guard service, you need...

canActivate(next: ActivatedRouteSnapshot,
          state: RouterStateSnapshot): Observable<boolean> {

      return this.auth.getIsUserLoggedIn() ? true : this.router.navigateByUrl('/login');
}

and in your authentication service, you need...

isLoggedin: boolean;

isLoggedIn(): Observable<boolean> {
  return new Observable((o) => {
    try {
     const cda = JSON.parse(localStorage.getItem('cda'));
     if (cda && cda.token) {
       console.log('Yes logged in');
       this.isloggedin = true;
       o.next(true);
     } else {
       console.log('Not logged in');
       this.isloggedin = true;
       o.next(false);
     }
    } catch (e) {
     console.log('Catch - Not logged in');
     o.next(false);
   }
 });

}

 getIsUserLoggedIn(){
     return this.isloggedin;
 }

Simply return true or false and redirect the user based on that.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using the Angular KeyValue pipe in a Material table to showcase arrays of objects

I have a response object that contains various data for different categories: { NET_TIME: [ { createdBy: 'Alex', from: '9.0', to: '8.0' }, { createdB ...

The mystery of Angular 2: Unveiling why ActivatedRoute.params always returns an empty object

I've been facing an issue with accessing the :id route parameter in a router guard. It seems to always return an empty Object{}. Initially, I was unsure of how to approach this problem, so I referred to this question for guidance. However, it didn&ap ...

Cypress: Uncovering the method invoked by a button click

I'm currently utilizing Vue3 with Vite and Cypress. My Vue3 component utilizes the script setup SFC syntax. Below is the code snippet for my component: <template> <div> <button data-cy="testBtn" @click="btnClick()&q ...

Compare two lists in Angular 4 and verify all the elements that are common in both

Two lists are in my possession roles{admin, guest, configuration manager}(contains all roles of the system) loggedInUserRoles {admin , guest}(holds the roles of the currently logged in user) Within a user edit form, there is a checkbox for each user. M ...

Eliminate any values that have not been chosen from the dropdown array in ngx-select-dropdown

Scenario: The challenge involves managing selected values in Angular applications using the ngx-select-dropdown. Users can select multiple values, which are then sorted into "buckets" and sent to the API. Problem: I'm facing difficulty removing a sel ...

When utilizing from(myPromise) with RxJs, is it necessary to unsubscribe?

When working with Angular, I often utilize the async pipe or takeUntil(...) on components like this: export class BaseComponent implements OnDestroy { ngUnsubscribe = new Subject<void>(); ngOnDestroy(): void { this.ngUnsubscribe.next(); ...

Is there a way to implement depth-first retrieval in rxjs using the expand method?

Currently, I am engaged in a project utilizing Angular 7, Typescript, and RxJS 6.3.3. In this project, I am working with RxJS Observables and relevant operators to handle hierarchical collections of objects obtained from an http server that interfaces with ...

Looking to retrieve the request body in a route handler in Next.js version 13.2?

I encountered an issue while attempting to send a post request to my API. The problem arises when I try to access the request body within the route handler, resulting in the following error: Code: export async function POST(request: Request) { const ...

Angular: handling asynchronous errors when no promise is utilized within a subscription

I am currently working with a material design table and have created custom functions to load the data and extract objects from a JSON array object. Here is a snippet of the code I am using: public getDocumentList() { return this.http.get(this.getDocu ...

Angular 2: Filtering a List Using Dynamic Values

I'm having trouble creating a list in Angular 2 and filtering the data when I input a value into a text field. I tried using pipes for filtering, but it's not working as expected. Can someone please help me identify what I'm doing wrong? ht ...

Why does TypeScript not generate an error if props are not passed to a functional component?

How does TypeScript handle not passing down props to a functional component without throwing an error? Consider the following code snippet: interface Props{ id: string; className?: string; } export const Buttons: React.FC<Props> = () => { r ...

The schematic "library" was not located within the collection "@schematics/angular"

While attempting to create a library in Angular CLI, I encountered the following error: Schematic "library" not found in collection "@schematics/angular". Error: Schematic "library" not found in collection "@schematics/angular". at SchematicEngine.cre ...

Reinitializing various states using React Redux

My application consists of multiple Steps, each with their own state. I am attempting to create a link that triggers an onClick Action to reset all states back to their initial values. However, I am facing difficulties in achieving this. Within my Nav, I ...

Permitted the usage of a global variable of any type as the return value of a function that does not explicitly define its

Here's a snippet of TypeScript code that compiles successfully: let testVar: any; const testFunc: () => number = () => { return testVar; }; Why does this code compile without errors? What is the reasoning behind it? ...

Establish a connection between a React variable and state management

In my codebase, I have an external module file named Task.ts. It contains the following: const taskList: Task[] = []; Class Task { ... } export { Task, taskList } The taskList is a list of Task objects that can be modified by the Task class. Now, i ...

Create a placeholder class for the Form Builder group component within an Angular application

Currently, I am in the process of creating numerous new forms. For instance: constructor(private formBuilder: FormBuilder) { this.userForm = this.formBuilder.group({ 'name': ['', Validators.required], 'email&apo ...

Function in Typescript that can return multiple data types

I recently started learning about TypeScript and its concepts. During my practice sessions, I encountered a problem that left me puzzled. There is a function named `functionA` which returns an object based on the response received from an API. type Combina ...

Typescript is throwing an error stating that the type 'Promise<void>' cannot be assigned to the type 'void | Destructor'

The text editor is displaying the following message: Error: Type 'Promise' is not compatible with type 'void | Destructor'. This error occurs when calling checkUserLoggedIn() within the useEffect hook. To resolve this, I tried defin ...

Tips for updating components with fresh data in Next.JS without having to refresh the page

As part of my Todo-App development project, I am utilizing technologies such as Next.JS, Prisma, Typescript, and PostgreSQL. The data retrieval process involves the API folder interacting with the database through Prisma. CRUD operations on the Task table ...

Dealing with Cross-Origin Resource Sharing Problems in Angular 8 REST API

I am currently working with 2 components: The first component, "CurrenciesComponent," is being loaded. @Component({ selector: 'app-currencies', templateUrl: './currencies.component.html', styleUrls: ['./currencies.componen ...