Creation of AoT-compliant service factories

I am trying to create a factory service for a cache service. The basic requirement is that each service can be installed with a different string each time.

The end result will have multiple cache services , each defined uniquely databaseName

. Each cache can have one or more stores , also identified as unique storeName

. Other services will be able to use these stores:

mainCache                         = new Cache('main')
  ├── userStore                   = new Store(mainCache, 'user')
  │     ├── userService
  │     └── authenticationService
  └── taskStore                   = new Store(mainCache, 'task')
        └── taskService

fooCache                          = new Cache('foo')
  └── barStore                    = new Store(otherCache, 'bar')

      

My current implementations are as follows:

//indexeddb-cache.ts
import { Injectable } from '@angular/core';

@Injectable()
export class IndexedDBCache {
  constructor(
    protected databaseName : string
  ) {}
}

// indexeddb-store.ts
import { Injectable } from '@angular/core';
import { IndexedDBCache } from './indexeddb-cache';

@Injectable()
export class IndexedDBStore {
  constructor(
    protected database : IndexedDBCache,
    protected storeName : string
  ) {}
}

      

Services are factored:

// test-api.cache.factory.ts
import { IndexedDBCache } from '../indexeddb-cache/indexeddb-cache';
import { IndexedDBStore } from '../indexeddb-cache/indexeddb-store';

// factory functions for FactoryProviders as exports instead of inline:
// https://github.com/rangle/angular-2-aot-sandbox#func-in-providers-usefactory-top
export function mainIndexedDBCacheFactory() { return new IndexedDBCache('main'); }
export function userIndexedDBStoreFactory(testIndexedDBCache: IndexedDBCache) { return new IndexedDBStore(testIndexedDBCache, 'user'); }
export function taskIndexedDBStoreFactory(testIndexedDBCache: IndexedDBCache) { return new IndexedDBStore(testIndexedDBCache, 'task'); }

      

And then provided:

// test-api.cache.ts
import { InjectionToken, Provider } from '@angular/core';
import { IndexedDBCache } from '../indexeddb-cache/indexeddb-cache';
import { IndexedDBStore } from '../indexeddb-cache/indexeddb-store';
import { mainIndexedDBCacheFactory,
         taskIndexedDBStoreFactory,
         userIndexedDBStoreFactory } from './test-api.cache.factory';

// Caches

export const mainIndexedDBCache = new InjectionToken<IndexedDBCache>('mainIndexedDBCache');

export let mainIndexedDBCacheProvider : Provider = {
  provide: mainIndexedDBCache,
  useFactory: mainIndexedDBCacheFactory
};

// Stores

export const userIndexedDBStore = new InjectionToken<IndexedDBStore>('userIndexedDBStore');

export let userIndexedDBStoreProvider : Provider = {
  provide: userIndexedDBStore, deps: [mainIndexedDBCache],
  useFactory: userIndexedDBStoreFactory
};

export const taskIndexedDBStore = new InjectionToken<IndexedDBStore>('taskIndexedDBStore');

export let taskIndexedDBStoreProvider : Provider = {
  provide: taskIndexedDBStore, deps: [mainIndexedDBCache],
  useFactory: taskIndexedDBStoreFactory
};

      

Declared in the main module:

// test-api-module.ts
import { NgModule, ModuleWithProviders } from '@angular/core';
import { mainIndexedDBCacheProvider,
         taskIndexedDBStoreProvider,
         userIndexedDBStoreProvider } from './test-api.cache';

@NgModule({
  imports: [], declarations: [], exports: []
})
export class TestAPIModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: TestAPIModule,
      providers: [
        mainIndexedDBCacheProvider,
        userIndexedDBStoreProvider,
        taskIndexedDBStoreProvider
      ]
    };
  }
}

      

And finally, it is used in the service:

//user-service/user.service.ts
import { Inject, Injectable } from '@angular/core';
import { IndexedDBStore } from '../../indexeddb-cache/indexeddb-store';
import { userIndexedDBStore } from '../test-api.cache';

@Injectable()
export class UserService {
  constructor(
    @Inject(userIndexedDBStore) protected cache : IndexedDBStore
  ) {}
}

      

Everything works fine when using JIT compilers. When I try to compile AoT, I start getting Warning: Can't resolve all parameters for x in y: (?). This will become an error in Angular v5.x

for cache and storage string options.

I have detailed my problem in this question: Toxify for AoT compilation . Now, this is similar to using strings, as the parameters for are @Injectable()

completely impossible with the AoT compiler. Is there any other way to create a factory for services initialized using a string as I described?

I have created a workable example in this repository . Checkout aot

and npm install

and then npm run build.prod.rollup.aot

should work just like that.

+3


source to share


1 answer


Based on user feedback @estus and @Toxicable Factory

, there shouldn't be a class to be set with only @Injectable

. Removing this tag from the classes IndexedDBCache

and IndexedDBStore

solve the problem.


Factory

must also be in a specific form

export function mainIndexedDBCacheFactory() { return new IndexedDBCache('main'); }

      



Other iterations of this definition will not work.

export const mainIndexedDBCacheFactory = function() { return new IndexedDBCache('main'); };
export let mainIndexedDBCacheFactory   = function() { return new IndexedDBCache('main'); };
export let mainIndexedDBCacheFactory   = () => new IndexedDBCache('main');

      

A export

prefix is
required even if the definition is in the same file as Provider

.

+2


source







All Articles