首页 > 解决方案 > DowngradeModule 和 downgradeInjectable 导致 Angular/AngularJS 混合应用程序中每个模块的单例服务,而不是全局单例

问题描述

情况:

我正在开发一个以 AngularJS 为核心的混合项目,其中应用程序需要慢慢升级到 Angular 9。因此必须降级新的 Angular 模块才能访问 AngularJS。AngularJS 应用程序由多个模块和子模块组成。这里只是 core(shared) 模块和 app.module 用于简化:

core.ng2.module.ts

@NgModule({
    imports: [
        CommonModule
    ],
    declarations: [
        ModuleBootstrapComponent
    ],
    entryComponents: [
        ModuleBootstrapComponent
    ]
})
export class CoreNg2Module {

    constructor() {
    }

    public ngDoBootstrap(): void {
    }
}

let rootInjectorPromise: Promise<Injector>| null = null;
const getRootInjector = (extraProviders: StaticProvider[]) => {
    if (!rootInjectorPromise) {
        rootInjectorPromise = platformBrowserDynamic(extraProviders)
            .bootstrapModule(AppNg2Module)
            .then(moduleRef => moduleRef.injector);
    }
    return rootInjectorPromise;
};

const bootstrapCoreFn = async (extraProviders: StaticProvider[]) => {
    const rootInjector = await getRootInjector(extraProviders);
    const moduleFactory = await rootInjector.get(Compiler).compileModuleAsync(CoreNg2Module);
    return moduleFactory.create(rootInjector);
};

const downgradedCoreNg2Module = downgradeModule(bootstrapCoreFn);

export const coreNg2ModuleName =
    angular
        .module('core.ng2', [
            downgradedCoreNg2Module
        ])
        .directive('moduleBootstrap',
            downgradeComponent({
                component: ModuleBootstrapComponent,
                downgradedModule: downgradedCoreNg2Module
            }))
        .name;

app.module.ts

@NgModule({
    imports: [
        BrowserModule,
        CommonModule,
        CoreNg2Module,
    ]
})
export class AppNg2Module {

    constructor() {
    }

    public ngDoBootstrap(): void {
        // Don't use this lifecycle hook since the hybrid app is bootstrapped manually inside Bootstrap.ts.
    }
}


export const appModuleName = angular
    .module('app.ng2', [
        coreNg2ModuleName,
    ]).factory('translateSyncService',
        downgradeInjectable(TranslateSyncService))
    .name;

目前的问题:

我根据官方指南降级并引导模块:https : //angular.io/api/upgrade/static/downgradeModule#downgrading-multiple-modules 让我的 app.module 作为我的 TranslateSyncService 的“根”。因为根据这个https://angular.io/guide/upgrade#how-ngupgrade-works单例服务在 AngularJS 和 Angular 之间共享,如果它们在“根”中提供。我需要 translate-sync-service 来将 Angular 组件的状态与 AngularJS 应用程序同步。

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

    languageSource = new BehaviorSubject<string>('en');
    usedLanguage$ = this.languageSource.asObservable();

    constructor() {
    }


    changeLanguage(language: string) {
        this.languageSource.next(language);
    }
}

我降级了模块和服务,使其可以在 AngularJS 中访问。问题是服务正在工作,但每个模块都有自己的服务实例,而不是全局单例服务。所以核心模块有自己的服务和我创建的每个其他模块。

tldr; 我最终得到每个模块的单例服务,而不是全局服务。

我的愿望:我想要一个 Angular 服务,它是跨降级的 Angular 模块和 AngularJS 应用程序的单例。

有人有这个问题的经验吗?

标签: angularjsangularsingletoninjectable

解决方案


我知道这很旧,但我遇到了同样的问题。我找到了一个对我有用的答案(类似情况)。我们使用我们注入到 Angular JS 应用程序中的降级模块的通用模式。(在其他地方有很多这样的例子)。

export const downgradedAngularAppModule = angular.module('downgraded-angular-module', [downgradedAngularModule])
                                                 .service('SomeAngularXService', downgradeInjectable(SomeAngularXService))

然后在 angularJS

export const angularJsModule: ng.IModule = angular.module(angularjsAppModule, [list of angularJS modules, downgradedAngularAppModule.name])

虽然仍处于混合模式,但我们正在 Angular JS 中引导 Angular。在单例 angular X 服务中,确保您使用以下内容进行装饰:

@Injectable(
    { providedIn: 'root' } // this means app wide singleton
)

如果您希望在您的 angularJS 应用程序中使用相同的服务实例,在您已迁移到 angular X 的组件中,而不是像这样直接导入模块:

import { SomeAngularXService } from 'SomeAngularXService.service.ts'

并将其注入您的构造函数中:

constructor(private someAngularXService: SomeAngularXService)

您应该改为在构造函数中使用 angularJS 实例

constructor(@Inject('SomeAngularXService') private someAngularXService: any)

你需要记住在你的 app.module.ts 中提供它

{
    provide: 'SomeAngularXService',
    useFactory: ($injector: any) => $injector.get('SomeAngularXService'),
    deps: ['$injector']
}

推荐阅读