angulardependency-injectionserver-side-renderingdocumentangular-dependency-injection

Injecting document into angular service for SSR


I am creating an angular library that has a root-level service class that references document. I'd like to add SSR support, but of course document is not defined in SSR context. It seems that Angular will allow me to dependency inject document into my service with the DOCUMENT injection token.

So now my service looks like.

import { DOCUMENT } from '@angular/common';

class MyService {
  private config: MyConfig;

  constructor(
    config: MyConfig,
    @Inject(DOCUMENT) private document: Document,
  ) {
    this.config = config;
  }
}

My question is this: where does document get injected into my service? My module definition now looks like this, but I know this is not correct because document is undefined at the callsite.

class MyModule {
  static forRoot(config: MyConfig): ModuleWithProviders<MyModule> {
    return {
      ngModule: MyModule,
      useValue: new MyService(
        config,
        document, // causes ReferenceError with SSR
      ),
    };
  }
}

Solution

  • Instead of manually instantiating the service, I can let Angular do it. It will handle injecting document into the service. Update the module forRoot definition like so:

    export class MyModule {
      static forRoot(config: MyConfig): ModuleWithProviders<MyModule> {
        return {
          ngModule: MyModule,
          providers: [
            { provide: 'MyConfig', useValue: config },
            MyService, // Angular will automatically inject DOCUMENT and the provided config
          ],
        };
      }
    }
    

    Both parameters will be injected. The MyService signature should be updated like so:

    import { DOCUMENT } from '@angular/common';
    
    class MyService {
      private config: MyConfig;
    
      constructor(
         @Inject('MyConfig') config: MyConfig,
         @Inject(DOCUMENT) private document: Document,
      ) {
        this.config = config;
      }
    }