0

I defined a resolver in my Angular (v13) app to do some shenanigans with a wordpress backend. When the user accesses an URL I want the resolver to check post type and ID from wordpress and route accordingly (post list, single post, page, ...).

To do that I have injected Angular's Router in my WordpressResolver class, but when I call router.navigate(...) I get the following error :

ERROR TypeError: Cannot read properties of undefined (reading 'navigate')

It seems like the router is not injected, but I cannot figure out why. I added the @Injectable decorator on my resolver and provided it in the routing module.
Here are my routing module and resolver code.

app.module.routing.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { NotFoundComponent } from './modules/not-found/not-found.component';
import { WordpressResolver } from './wordpress-resolver';

const routes: Routes = [
  {
    path: 'posts',
    loadChildren: () =>
      import('./modules/posts/posts.module').then((m) => m.PostsModule),
  },
  {
    path: 'single/:id',
    loadChildren: () =>
      import('./modules/post/post.module').then((m) => m.PostModule),
  },
  {
    path: 'page/:id',
    loadChildren: () =>
      import('./modules/page/page.module').then((m) => m.PageModule),
  },
  {
    path: '**',
    component: NotFoundComponent,
    resolve: {
      error: WordpressResolver,
    },
  },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: [WordpressResolver],
})
export class AppRoutingModule {}

wordpress-resolver.ts

import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import {
  ActivatedRouteSnapshot,
  Resolve,
  Router,
  RouterStateSnapshot,
} from '@angular/router';
import { environment } from 'src/environments/environment';
import { UrlData } from './shared/model/url-data.interface';
import { UrlType } from './shared/model/url-type.enum';

@Injectable({ providedIn: 'root' })
export class WordpressResolver implements Resolve<HttpErrorResponse | null> {
  constructor(private http: HttpClient, private router: Router) {}

  private error: HttpErrorResponse | null = null;

  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): HttpErrorResponse | null {
    this.http
      .get<UrlData>(environment.domain + state.url)
      .subscribe(this.resolveSuccess, this.resolveError);

    return this.error;
  }

  private resolveSuccess(urlData: UrlData): void {
    switch (urlData.type) {
      case UrlType.POSTS:
        this.router.navigate(['/posts'], { skipLocationChange: false });
        return;
      case UrlType.POST:
        this.router.navigate(['/post', urlData.id], {
          skipLocationChange: false,
        });
        return;
      case UrlType.PAGE:
        this.router.navigate(['/page', urlData.id], {
          skipLocationChange: false,
        });
        return;
      default:
        return;
    }
  }
  private resolveError(error: HttpErrorResponse): void {
    this.error = error;

    this.router.navigate(['/error'], {
      skipLocationChange: true,
    });
  }
}

(I know '/error' is not mapped yet, this is a work in progress)

2 Answers 2

1

You have to define your callback function as arrow function so that you can access global scope

resolveSuccess= (urlData: UrlData): void => { }

Sign up to request clarification or add additional context in comments.

Comments

0

This is the culprit:

 .subscribe(this.resolveSuccess, this.resolveError);

The methods will be "copied" to another scope where this.router does not exist.

Solution:

.subscribe((success)=>this.resolveSuccess(success),(error)=> this.resolveError(error));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.