Создайте одноэлементный сервис без необходимости внедрять его в Angular 7 - PullRequest
1 голос
/ 11 июня 2019

Ситуация

Я пытался найти способ, с помощью которого я мог бы создать службу, которая будет просто сидеть «на заднем плане» и слушать события (и делать что-то) - кем бы я хотел бытьсоздан, когда приложение инициализируется, и о нем забывают.

К сожалению, мне нужно использовать внедрение зависимостей в компонент для создания экземпляра службы - большинство путей, которые я использую, приводят к использованию AppComponentКонструктор.

Хотя я не буду напрямую взаимодействовать со службой (вызывая методы / свойства) и хочу не допускать ее к другим компонентам / службам, которые не имеют к ней никакого отношения.


Служба

Служба и логика в ней довольно просты.Мой сервис основан на Динамических заголовках страниц в учебнике по Angular 2 .

Сервис будет прослушивать NavigationEnd события из Router, захватывать ActivatedRoute и затем использоватьданные маршрута для установки заголовка страницы.

В отличие от примера из учебника, я создал собственный сервис вместо того, чтобы помещать логику в AppComponent;Я хочу сохранить разделение проблем наверх.

page-title.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']));
  }

}

Очевидно, что сама служба будет полагаться на внедрение зависимостей для использования Router, ActivatedRoute и Title.


Проблема

Единственный способ, которым я в настоящее время знаю, для создания экземпляра этого сервиса - использовать внедрение зависимостей в другой компонент / сервис.

Например, 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
  }

}

Проблема в том, что я хочу избежать этого, если это вообще возможно.


Вопрос

Можно ли создать экземпляр службы где-нибудь, кроме компонента / службы?


Возможность?

У меня есть 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 { }

Могу я, возможно, создать экземпляр PageTitleService здесь, где-нибудь?

Или, есть ли лучшее место / способ сделать это?

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 11 июня 2019

Возможно ли вам создать title.ts в корневой папке и сделать:

export const titleConfig = {
  title: '',
}

и обращаться к этому объекту в любое время, когда вам это нужно, и изменять его в маршрутизаторе

import { titleConfig } from 'src/app/title';
// ...more magic goes here

export class PageTitleService {

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

        return route;
      })
      .filter((route) => route.outlet === 'primary')
      .mergeMap((route) => route.data)
      .subscribe((routeData) => titleConfig.title = routeData['title']); // change here
  }

}

если вы используете ChangeDetectionStrategy.Onpush, тогда вы можете сделать { ...routerData['title'] } или добавить setTitle метод к объекту.Я не уверен.

0 голосов
/ 11 июня 2019

Используйте APP_INITIALIZER или APP_BOOTSTRAP_LISTENER . Подробнее вы можете найти здесь .

Для использования Router в APP_INITIALIZER установить initialNavigation для true. Или используйте APP_BOOTSTRAP_LISTENER (но в этом случае вы пропускаете первую навигацию)

для добавления инициализатора необходимо добавить провайдера для него

{
  provide: APP_INITIALIZER,
  useFactory: (router) => yourFunction,
  multi: true,
  deps: [Router]
}
...