Issue with service being undefined upon refreshing an Angular 9 application that includes a resolver in its routing logic

Having a Component that loads user data and needs to handle direct access via URL, I implemented a resolver service in the router. It works fine when accessing the component through routing within the application. But upon refreshing the page with the URL, the resolver service throws this error:

ERROR Error: "Uncaught (in promise): TypeError: this.userService.getCurrentUser() is undefined

It seems like the userService isn't initialized quickly enough during refresh.

Here's the code for the resolver service:

@Injectable({
  providedIn: 'root'
})
export class UserResolverService {

 constructor(private userService: UserService, private authService: AuthService, private router:Router) { }

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<User> | Observable<never> {
let id = route.paramMap.get('id');


 //return this.authService.checkToken().subscribe(res => {
if(this.authService.checkToken()){
  return this.userService.getCurrentUser().pipe(take(1), mergeMap(user => {
    if(user){
      return of(user);
    } else {
      this.router.navigate['/login'];
      return EMPTY;
    }
  }));
} else {
  this.router.navigate['/login'];
      return EMPTY;
}

 }

 }

This is the method called in UserService:

getCurrentUser(): Observable<User>{
if(this.currentUser.value != null){
  return this.currentUser.asObservable().pipe(filter(user => user != null));
} else {
  this.setCurrentUser().subscribe(res => {
    return this.currentUser.asObservable().pipe(filter(user => user != null));
  })
}

The setCurrentUser() method calls the backend with credentials to retrieve user data.

The constructor of the Component that should load its data upon refreshing contains the following:

this.route.data.subscribe((data: {user: User}) => {
  this.user = data.user;
  this.initialDialogWindows();
  this.initialViewGuidingVariables();
});

EDIT:

I updated it with the solution from Aakash Garg. Now, the ngOnit() methods only receive undefined and the resolver doesn't wait for promises. None of the console logs other than "am I even here?" are executed.

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<User> {
let id = route.paramMap.get('id');


 //return this.authService.checkToken().subscribe(res => {
if(this.authService.checkToken()){
  console.log("am I even here?");
   this.userService.getCurrentUserPromise().then(user => {
     console.log("resolved user:" + user);
    if(user){
      return of(user);
    } else {
      console.log("navigating to login");
      this.router.navigate['/login'];
      return EMPTY;
    }
  });
} else {
  console.log("navigating to login, because there is no token");
  this.router.navigate['/login'];
      return EMPTY;
}

 }

Answer №1

It's not a problem with service initialization, but rather the way in which your getCurrentUser method is implemented. When currentUser.value is null, it doesn't wait for the subscription to finish and returns undefined. This is how asynchronous tasks operate. Update your getCurrentUser method to:

    async getCurrentUser(): Promise<User> {
      if(this.currentUser.value != null) {
        return this.currentUser.asObservable().pipe(filter(user => user != null)).toPromise();
      } else {
        await this.setCurrentUser().toPromise();
        return await this.currentUser.asObservable().pipe(filter(user => user != null)).toPromise();
      }
    }

Also, modify your resolver as follows:

@Injectable({
  providedIn: 'root'
})
export class UserResolverService {

 constructor(private userService: UserService, private authService: AuthService, private router:Router) { }

 resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<User> | Observable<never> {
  let id = route.paramMap.get('id');

  if(this.authService.checkToken()) {
    this.userService.getCurrentUser().then(user => {
      if(user) {
        return of(user);
      } else {
        this.router.navigate['/login'];
        return EMPTY;
      }
    });
  } else {
    this.router.navigate['/login'];
    return EMPTY;
  }
 }
}

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

Utilizing Angular's intelligent dichotomy of (container) and (presentational) components, integrating conditional logic, and effectively passing inputs throughout the

Imagine you have two simple components, A and B. Component C will only display either component A OR B, which is controlled by smart component D. D (smart) | C (simple) / \ A B (both simple) Both components A and B have 10 inputs each. Ther ...

Using Angular to assign a CSS variable to the before/after pseudo-classes

Having trouble passing a variable with [ngStyle] and reading it on the ::before class, any guidance in the right direction would be much appreciated! CSS: .handle-slider__control { height: 7px; z-index:1; background: $colour-alto; positi ...

Angular2: Error - trying to access 'this.' which is not defined

I have a function that is designed to retrieve and display the "best player" from an array of objects, which essentially refers to the player with the most likes. The functionality of this function works as intended and displays the desired output. However ...

Error in Writing Functional Components with Typescript in React

I am struggling to create a versatile functional component and encountering issues like the one shown in this https://i.stack.imgur.com/WQkKg.png: Here is the code snippet: interface IAppTable<Type> { height: number; data: Type[]; tableLayout: ...

How do I inform Jest that spaces should be recognized as spaces?

Here is some code snippet for you to ponder: import { getLocale } from './locale'; export const euro = (priceData: number): string => { const priceFormatter = new Intl.NumberFormat(getLocale(), { style: 'currency', currenc ...

When adjusting the month/year, the Material Date Picker extends beyond its container

Currently, I have an Angular 18 application with a page that includes a material date picker component. When I open the Date Picker, everything displays correctly. However, when I try to change the month using the left/right arrow or the year, the data co ...

Utilizing the arr.push() method to replace an existing value within an array with a new object, rather than simply adding a new

Seeking help to dynamically render a list of components that should expand or shrink based on values being added or removed from an array of custom objects. However, facing an issue where pushing a value into the array only replaces the previous value inst ...

Getting the latest data from a Kendo Dialog in Angular 4

I am passing the 'TotalUnits' value to the Dialog and updating it there. However, I am having trouble retrieving the updated value back in the 'dialog.result'. Can anyone provide some assistance? Main Component: Open AllocationDialog( ...

Using the parameter of type 'never' is necessary as per the TypeScript error message, which states that the argument of type 'string' cannot be assigned to it. This error persists even when

https://i.sstatic.net/tkX07.png const index = selectedActivities.value.indexOf(activity_id); I encountered a TypeScript error saying 'Argument of type 'string' is not assignable to parameter of type 'never'. How can I fix this iss ...

Declaring TypeScript functions with variable numbers of parameters

Is it possible to define a custom type called OnClick that can accept multiple types as arguments? How can I implement this feature so that I can use parameters of different data types? type OnClick<..> = (..) => void; // example usage: const o ...

Encounter the "Error: Source 'cloudsTileLayer-RasterSource' not found" message while trying to integrate a weather tile layer into Azure Maps

I have been working on a React application that utilizes the React-Azure-Maps npm package. My current challenge involves creating a weather layer, which I believe shares similarities with the sample code provided for layers. The code snippet responsible f ...

Equalizing Lists in Angular 2

Struggling to locate documentation on this topic, but in Angular 1 it was possible to achieve the following: <textarea ng-model="name" ng-list=","></textarea> With this setup, if you were to input "Hello, world!" into the textarea, the name v ...

The error message "ng2-test-seed cannot be found - file or directory does not exist"

I've been attempting to work with an angular2 seed project, but I'm encountering some challenges. https://github.com/juliemr/ng2-test-seed When I run the command: npm run build I encounter the following error: cp: cannot stat ‘src/{index.h ...

Creating Angular components and attaching them to the body tag is a simple yet

My goal is to create a component at the root element of the page. I have come across some resources that are similar to what I need, but they use the DynamicComponentLoader which is now considered deprecated. public component: any; constructor( public ...

Dealing with performance issues in React Recharts when rendering a large amount of data

My Recharts use case involves rendering over 20,000 data points, which is causing a blocking render: https://codesandbox.io/s/recharts-render-blocking-2k1eh?file=/src/App.tsx (Check out the CodeSandbox with a small pulse animation to visualize the blocki ...

Encountering an error in Jest with TypeScript (Backend - Node/Express) that reads "Cannot use import statement outside a module

Currently, I am in the process of developing Jest tests for a Node/Express TypeScript backend. Recently, I came across the concept of global test setup which I am integrating to streamline the usage of variables and function calls that are repeated in all ...

Angular projects experience issues with importing date-fns which results in failing Jest tests

After updating one of my Angular projects to version 13, I encountered strange errors while running unit tests in the project. To better understand this issue, I created a simple example within a new Angular project: import { format } from 'date-fns& ...

Learn the steps to disable web page preview in Telegram bot using Node.js

Hey there everyone, just a heads up that my English might not be perfect. Currently working on some nodejs coding and trying to figure out where exactly I should include the disable_web_page_preview in my code. Any ideas? Telegram.prototype.sendIn = asyn ...

Could a template variable be established for the p-dropdown element in template-driven form validation?

In the template, I have a p-dropdown element <p-dropdown id="output-method" [options]="outputMethods" [(ngModel)]="transformer!.outputMethod" pTooltip="Output Method" tooltipPosition="bottom&quo ...

Develop a user interface that includes the ability to have unspecified properties of an unspecified data type,

interface Sample { value?: string [prop: string]: any } const sampleObject: Sample = { title: 'John' } const data = sampleObject.title By including "any" in the interface, it eliminates the automatically assumed "string" type for the p ...