0

I want to override the function navigate(commands: any[], extras?: NavigationExtras): Promise<boolean> of Router to always set queryParamsHandling to true in the NavigationExtras.

Therefore I implemented following class:

@Injectable({
    providedIn: 'root'
})
export class MmosRouter extends Router {

    constructor(
        rootComponentType: Type<any>,
        urlSerializer: UrlSerializer,
        contexts: ChildrenOutletContexts,
        location: Location_2,
        injector: Injector,
        compiler: Compiler,
        @Inject(ROUTES) config: Route[][]
    ) {
        super(rootComponentType, urlSerializer, contexts, location, injector, compiler, flatten(config));
    }


    navigate(commands: any[], extras?: NavigationExtras): Promise<boolean> {
        extras = { ...extras, queryParamsHandling: 'preserve' };
        return super.navigate(commands, extras);
    }
}

Because I want to inject the class through a components constructor I have to add the class to providers in app.module.ts.

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
  ],
  providers: [
    ...
  {
    provide: Router,
    useFactory: (rootComponentType: Type<any>, urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location_2, injector: Injector, config: Route[][]) => {
      return new MmosRouter(rootComponentType, urlSerializer, contexts, location, injector, config);
    },
    deps: [ApplicationRef, UrlSerializer, ChildrenOutletContexts, Location_2, Injector, Compiler, ROUTES]
  },
    ...
  ],
  bootstrap: [...],
  exports: [
    ...
  ],
})
export class AppModule {
  constructor(service: ApmService) {}
}

For my information, that should be everything to get this to work.

However, whenever I start the application, I get following NullInjectionError:

core.mjs:9171 ERROR NullInjectorError: R3InjectorError(AppModule)[MmosRouter -> Function -> Function -> Function]: 
NullInjectorError: No provider for Function!
  at NullInjector.get (core.mjs:8191:27)
  at R3Injector.get (core.mjs:8618:33)
  at R3Injector.get (core.mjs:8618:33)
  at R3Injector.get (core.mjs:8618:33)
  at injectInjectorOnly (core.mjs:4782:33)
  at Module.ɵɵinject (core.mjs:4786:12)
  at Object.MmosRouter_Factory [as factory] (mmosRouter.ts:17:24)
  at R3Injector.hydrate (core.mjs:8719:35)
  at R3Injector.get (core.mjs:8607:33)
  at ChainedInjector.get (core.mjs:13811:36)

(line 17, mentioned in the error, is the class signature of MmosRouting)

3 Answers 3

0

it seems you are trying to inject MmosRouter somewhere, and there is nothing that is provided by that token, and angular tries to resolve tokens from constructor parameters.

try

{
    provide: MmosRouter,
    useFactory: (rootComponentType: Type<any>, urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location_2, injector: Injector, config: Route[][]) => {
      return new MmosRouter(rootComponentType, urlSerializer, contexts, location, injector, config);
    },
    deps: [ApplicationRef, UrlSerializer, ChildrenOutletContexts, Location_2, Injector, Compiler, ROUTES]
  },
  {
    provide: Router,
    useExisting: MmosRouter
   }

this way your app would know how to construct MmosRouter and will provide same instance in place of Router

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

2 Comments

thanks for your answer, but unfortunately that won't work either. It doesn't even render the websites content. The exception now is: NullInjectorError: NullInjectorError: No provider for Function!
it seems you should skip the Compiler in deps config(there is no compiler in usual builds). also most probably ApplicationRef is not a valid argument for the rootComponentType, but that is the issue that you should get somewhere after
0

The problem was Type<any> in the constructor of MmosRouter.

Because Type is a FunctionConstructor and that interface has some properties with type Function, I think angular had problems to provide them when I wanted to inject my custom router.

So the Solution is removing the parameter rootComponentType: Type<any> from the constructor and pass AppComponent into the super(...) in the body. And then you also don't need them in the providers in app.module.ts.

So consider changing:

Custom Router:

@Injectable({
  providedIn: 'root'
})
export class MmosRouter extends Router {

  constructor(
    //remove rootComponentType: Type<any>
    ...
  ) {
    super(AppComponent, ...);
  }


  navigate(commands: any[], extras?: NavigationExtras): Promise<boolean> {
    ...
  }
}

Comments

0

There is no need for the below code block!

So app.module.ts will not contain the providers with the useFactory object!

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
  ],
  providers: [
    ...
  ],
  bootstrap: [...],
  exports: [
    ...
  ],
})
export class AppModule {
  constructor(service: ApmService) {}
}

You can simplify you service to the below code, where you import router and call the router method, just with the extra params, this will make your code less complex and more maintainable!

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

    constructor(private router: Router) { }


    navigate(commands: any[], extras?: NavigationExtras): Promise<boolean> {
        extras = { ...extras, queryParamsHandling: 'preserve' };
        return this.navigate(commands, extras);
    }
}

The above code will do the same thing!

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.