My angular app is running using server side rendering with Angular 17. Since location object is not available for redirecting, I am trying to inject request and response objects in to the app. I have implemented one redirect service which is given below.
import { Injectable, InjectionToken, Inject, PLATFORM_ID } from '@angular/core';
import { Router } from '@angular/router';
export const REQUEST = new InjectionToken<Request>('REQUEST');
export const RESPONSE = new InjectionToken<Response>('RESPONSE');
import { Response } from 'express';
import { isPlatformBrowser, isPlatformServer, DOCUMENT } from '@angular/common';
import { TransferState, makeStateKey } from '@angular/platform-browser';
@Injectable({
providedIn: 'root'
})
export class RedirectService {
constructor(
@Inject(RESPONSE) private response: Response,
@Inject(PLATFORM_ID) private platformId: Object,
@Inject(DOCUMENT) private document: any,
private transferState: TransferState
) {}
redirectToUrl(url: string): void {
if (isPlatformBrowser(this.platformId)) {
// Running in the browser
window.location.href = url;
} else {
// Running on the server
this.response.redirect(301, url);
}
}
isSSR() {
return isPlatformServer(this.platformId)
}
reload(): void {
if (isPlatformBrowser(this.platformId)) {
// Running in the browser
window.location.reload();
} else if (isPlatformServer(this.platformId)) {
// Running on the server
// Inject a script into the response that triggers a reload on the client side
const script = `<script>document.location.reload();</script>`;
const key = makeStateKey<string>('reloadScript');
this.transferState.set(key, script);
// Send a response with the script to trigger the reload
this.response.send(this.document.toString());
}
}
public redirect(url: string, router: Router) {
router.navigate(!Array.isArray(url)? [url]: url)
}
}
But when run on browser without SSR it is showing the following error in browser console.
ERROR NullInjectorError: R3InjectorError(AppModule)[RedirectService -> InjectionToken RESPONSE -> InjectionToken RESPONSE]:
NullInjectorError: No provider for InjectionToken RESPONSE!
I tried some solutions which asks to inject the Response object from the module file. One such solution is given below.
import { APP_ID, NgZone } from '@angular/core';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
import { SERVER_PLATFORM_PROVIDERS, PlatformService, INITIAL_CONFIG, platformDynamicServer } from '@angular/platform-server';
import { DOCUMENT } from '@angular/common';
import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';
// ...
providers: [
// ...
{ provide: PLATFORM_ID, useValue: 'server' },
{ provide: APP_ID, useValue: 'my-app-id' },
{ provide: DOCUMENT, useFactory: (doc: any) => doc || {}, deps: [NgZone] },
{ provide: INITIAL_CONFIG, useFactory: (doc: any) => ({ document: doc }), deps: [DOCUMENT] },
{ provide: PlatformService, deps: [DOCUMENT] },
{ provide: REQUEST, useFactory: (req: any) => req, deps: [] },
{ provide: RESPONSE, useFactory: (res: any) => res, deps: [] },
// ...
]
But since I am using Angular 17 and SSR, @nguniversal/express-engine/tokens
is no longer available.
How can this be solved. How to inject request and response objects to the component via module.
use nodemon and compile project
add this to "scripts" on package.json