无需在 Angular 7 中注入即可创建单例服务

Geo*_*mes 6 service singleton angular

情况

我一直在尝试找到一种方法,我可以实例化一个纯粹位于“后台”并侦听事件(并做一些事情)的服务——我希望在应用程序初始化时创建它,然后被遗忘.

不幸的是,我需要在组件中使用依赖项注入,以便实例化服务 - 我采用的大多数路径都导致使用AppComponent的构造函数。

我不会直接与服务交互(调用方法/属性),并希望将它与其他没有直接关系的组件/服务分开。


服务

服务和其中的逻辑非常简单。我的服务基于Angular 2教程中的动态页面标题

该服务将侦听NavigationEnd来自 的事件Router,抓取ActivatedRoute,然后使用路由的数据来设置页面标题。

与教程中的示例不同,我创建了自己的服务,而不是将逻辑放在AppComponent; 我想让我的关注点分离处于最佳状态。

页面标题.service.ts:

import { Injectable } from '@angular/core';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { filter, map, mergeMap } from 'rxjs/operators';

@Injectable()
export class PageTitleService {

  constructor(
    router: Router,
    activatedRoute: ActivatedRoute,
    titleService: Title
  ) {
    router.events
      .pipe(
        filter((event) => event instanceof NavigationEnd),
        map(() => activatedRoute),
        map((route) => {
          while (route.firstChild) {
            route = route.firstChild;
          }

          return route;
        }),
        filter((route) => route.outlet === 'primary'),
        mergeMap((route) => route.data)
      )
      .subscribe((routeData) => titleService.setTitle(routeData['title']));
  }

}
Run Code Online (Sandbox Code Playgroud)

显然,本身依靠依赖注入的服务才能使用RouterActivatedRouteTitle服务。


问题

我目前知道的实例化此服务的唯一方法是使用依赖注入到另一个组件/服务中。

例如app.component.ts

export class AppComponent implements OnInit {

  constructor(
    pageTitleService: PageTitleService, // inject the service to instantiate it
    // ... other services
  ) { }

  ngOnInit() {
    // do stuff with other services, but not the pageTitleService
  }

}
Run Code Online (Sandbox Code Playgroud)

问题是,如果可能的话,我想避免这样做。


是否可以在组件/服务以外的其他地方实例化服务?


可能性?

我确实有一个app-load.module.ts,它会在加载应用程序的其余部分之前进行一些前期初始化:

import { APP_INITIALIZER, NgModule } from '@angular/core';

import { OrganisationService } from './core/organisation/organisation.service';

export function initApp(organisationService: OrganisationService) {
  return () =>
    organisationService
      .initialize()
      .then(() => window.document.documentElement.classList.remove('app-loading'));
}

@NgModule({
  imports: [],
  declarations: [],
  providers: [
    OrganisationService,
    { provide: APP_INITIALIZER, useFactory: initApp, deps: [OrganisationService], multi: true }
  ]
})
export class AppLoadModule { }
Run Code Online (Sandbox Code Playgroud)

我可以PageTitleService在这里的某个地方实例化吗?

或者,有没有更好的地方/方法来做到这一点?

提前致谢。

izm*_*dev 0

使用APP_INITIALIZERAPP_BOOTSTRAP_LISTENER您可以在此处找到更多详细信息。

用于Router初始导航选项APP_INITIALIZER设置为。或者使用(但在这种情况下您跳过第一次导航)trueAPP_BOOTSTRAP_LISTENER

对于添加初始化程序,您需要为其添加提供程序

{
  provide: APP_INITIALIZER,
  useFactory: (router) => yourFunction,
  multi: true,
  deps: [Router]
}
Run Code Online (Sandbox Code Playgroud)

  • 您好@izmaylovdev,感谢您的回答。虽然我总是很感激有用的文章链接,但随着时间的推移,链接可能会失效——对于未来的访问者来说可能不是最有用的。此外,在 SO 的指南中,它不鼓励仅链接的答案。您能否扩展一下您的答案,以便我和其他用户可以快速从这些链接中参考一些有用的信息? (4认同)