0

I'm new to Angular5 and TypeScript, so it's very possible it's a simple thing I'm overlooking.

I have an Angular hybrid app that uses ngUpgrade to run AngularJS and Angular5 side-by-side. I'm trying to inject $templateCache into the OnAppInit function so that I can load all the AngularJS HTML templates before the app completely initializes. I'm getting the error "Cannot find name '$templateCacheService'" as indicated below. Is my syntax wrong or is this not possible?

I "upgrade" $templateCache in upgraded-providers.ts like this:

import { InjectionToken, Directive, ElementRef, Injector } from '@angular/core';
import { UpgradeComponent } from '@angular/upgrade/static';

export const $templateCacheService = new InjectionToken<any>('$templateCacheService');
export const $templateCacheServiceProvider = {
  provide: $templateCacheService,
  useFactory: (i: any) => i.get('$templateCache'),
  deps: ['$injector']
}; 

Then in app.module.ts, I try to inject it into OnAppInit:

import { NgModule, APP_INITIALIZER, Inject } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatCommonModule } from '@angular/material';
import { FlexLayoutModule } from '@angular/flex-layout';
import { HttpClientModule, HttpClient, HTTP_INTERCEPTORS } from '@angular/common/http';
import { downgradeInjectable, UpgradeModule, downgradeComponent } from '@angular/upgrade/static';
import { environment } from '../environments/environment';

import {
  $templateCacheServiceProvider,
  $templateCacheService
} from './upgraded-providers';
import { AppComponent } from './app.component';
import { GlobalVarsService } from './core/global-vars.service';
import { WinAuthInterceptor } from './core/interceptors/win-auth.interceptor';

declare var angular: any;

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatCommonModule,
    FlexLayoutModule,
    HttpClientModule,
    UpgradeModule
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: WinAuthInterceptor,
      multi: true
    },
    {
      provide: APP_INITIALIZER,
      useFactory: OnAppInit,
      multi: true,
      deps: [GlobalVarsService, HttpClient, $templateCacheService]
    },
    GlobalVarsService,
    $templateCacheServiceProvider
  ]
})
export class AppModule {
  constructor(private upgrade: UpgradeModule, private http: HttpClient) { }
  ngDoBootstrap() {
    angular.module('app').factory('globalVars', downgradeInjectable(GlobalVarsService));
    this.upgrade.bootstrap(document.body, ['app'], { strictDi: true });
  }
}

////// THIS NEXT LINE GETS error TS2304: Cannot find name '$templateCacheService' /////
export function OnAppInit(globalVars: GlobalVarsService, http: HttpClient, $templateCache: $templateCacheService) { 
  return (): Promise<any> => {
    return new Promise((resolve, reject) => {
      http.get(environment.apiBase + '/api/meta/data').subscribe(x => {
        globalVars.MetaData = x;
        globalVars.VersionNumber = globalVars.MetaData.versionNumber;
        globalVars.IsDebugBuild = globalVars.MetaData.isDebugBuild;
        globalVars.User = globalVars.MetaData.user;
        globalVars.ApiBase = environment.apiBase;
        globalVars.Templates.forEach(template => {
          $templateCache.put(template.Item1, template.Item2);
        });
        resolve();
      });
    });
  };
}
3
  • At least $templateCacheService is not a valid type here, $templateCache: $templateCacheService. I guess the type is something like ng.ITemplateCacheService. Commented Feb 13, 2018 at 1:17
  • @estus, I use the same approach for other ng1 services that I need to inject into ng5 components and it works fine. Why would it be different here? Commented Feb 13, 2018 at 14:38
  • It's not about approach. It's about proper typing. $templateCacheService is not a correct type (not a type at all). Commented Feb 13, 2018 at 15:05

1 Answer 1

1

This is TypeScript type error, it doesn't affect how the application works (as long as compilation errors are ignored).

templateCacheService is not a valid type here, because $templateCacheService is a variable (injection token), not a type or an interface.

Only Angular class constructors are annotated with types for DI. Since factory functions are annotated with deps property, types in function signature exist only to provide type safety. If it's not needed, types can be skipped:

export function OnAppInit(
  globalVars: GlobalVarsService, http: HttpClient,
  $templateCache
) { ... }

Otherwise proper types should be used. $templateCache is an object with get, put, etc methods. Appropriate types are provided with AngularJS @types/angular type definitions. It will be something like:

export function OnAppInit(
  globalVars: GlobalVarsService, http: HttpClient,
  $templateCache: ng.ITemplateCacheService
) { ... }
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, that makes sense. I took off the type and now I'm getting the error "Trying to get the AngularJS injector before it being set." Do you notice anything else that I'm missing?
You likely need .bootstrap() in ngDoBootstrap, since it presumes that you will do all the work manually. See for example stackoverflow.com/a/48328290/3731501 . Your module also doesn't have entryComponents

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.