Angular 2: Вложить зависимость в @CanActivate?

В Angular 2 вы можете указать аннотацию @CanActivate для компонента, где вы можете определить, должен ли компонент быть активирован или нет. Причина, по которой это не интерфейс, заключается в том, что обратный вызов вызывается до того, как компонент даже создается. Проблема в том, что я не могу найти способ получить зависимости, введенные в этот обратный вызов. И мне нужна моя служба, которая сообщает мне, вошел ли я в систему или нет (и как кто), чтобы определить, разрешена ли маршрутизация к определенному компоненту или нет.

Как я могу вставить зависимость в обратный вызов @CanActivate? Я использую ES5, и это не работает:

app.ListsComponent = ng.router.CanActivate([
    app.SessionService,
    function(session, instruction) {
        console.log(session);
        return true;
    }
])(app.ListsComponent);

Изменить: В качестве альтернативы я могу использовать событие жизненного цикла routerOnActivate для компонента и использовать this.router.navigate, чтобы отправить пользователя, если они не должны быть там. Недостатком является то, что он разбивает историю браузера: если я перенаправляю вас асинхронно каждый раз, когда вы достигаете определенного URL-адреса, вы не можете использовать кнопку "Назад" в своем браузере очень полезно. Есть ли способ router.navigate использовать history.replaceState вместо history.pushState для такого рода ситуаций?

Ответ 1

В большинстве решений здесь будут возникать проблемы с загрузкой подзависимостей из других источников иерархии, поскольку они создают новый инжектор. Кроме того, это приводит к добавлению дополнительных (не общих) сервисов. Я рекомендую следовать шаблону, представленному Брэндоном в https://github.com/angular/angular/issues/4112

Он ссылается на этот Plunk: http://plnkr.co/edit/SF8gsYN1SvmUbkosHjqQ?p=preview

Его основной идеей является инжектор с одним контуром, который он сохраняет, когда приложение инициализируется. Это обеспечивает доступ к уже установленным корневым зависимостям, а также позволяет использовать ваши сервисы как одноэлементные, поскольку они, вероятно, были предназначены:

import {Injector} from 'angular2/angular2';
let appInjectorRef: Injector;

export const appInjector = (injector?: Injector):Injector => {
    if (injector) {
      appInjectorRef = injector;
    }

    return appInjectorRef;
};

bootstrap([ServiceYouNeed]).then((appRef) => {
    // store a reference to the injector
    appInjector(appRef.injector);
});

Ответ 2

Вам нужно вводить его с помощью инжектора. Просто скопируйте копию из проекта, который я делаю:

@CanActivate((next: ComponentInstruction, prev: ComponentInstruction) => {

  console.info('CanActivate hook! - can return boolean or Promise');

  var injector = Injector.resolveAndCreate([HTTP_PROVIDERS, YourService]);
  var yourService = injector.get(YourService);
  // do something with yourService
  return new Promise(function(resolve, reject) {
      resolve(true);
  });

})

HTTP_PROVIDERS вы должны пройти, если ваша служба, например, введет HTTP-сервис в конструктор.

Я использую его, чтобы поместить наблюдаемый параметр params следующего объекта. И следующий объект - ваш следующий "компонент/состояние":

@CanActivate((next: ComponentInstruction, prev: ComponentInstruction) => {

  console.info('properties component CanActivate hook! - can return boolean or Promise');
  var injector = Injector.resolveAndCreate([HTTP_PROVIDERS, PropertiesService]);
  var propertiesService = injector.get(PropertiesService);
  return new Promise(function(resolve, reject) {
      next.params['properties'] = propertiesService.getProperties();
      resolve(true);
  });

})

Функция PropertiesService вызывает бэкэнд и возвращает Observable, который представляет данные со свойствами

Ответ 3

Я не знаю, лучший ли это, но эти ребята делают это, расширяя и используя свой собственный <router-outlet> и переопределяя метод CanActivate:

https://auth0.com/blog/2015/05/14/creating-your-first-real-world-angular-2-app-from-authentication-to-calling-an-api-and-everything-in-between/

Также вы можете использовать routerOnActivate.

https://angular.io/docs/js/latest/api/router/OnActivate-interface.html Надеюсь, это поможет.

Ответ 4

Здесь (https://gist.github.com/clemcke/c5902028a1b0934b03d9) заключается в том, как проверить решение addInjector(), которое ссылается на @shannon:

beforeEachProviders(()=>[PERSON_SERVICE_PROVIDERS]);

beforeEach(inject([PersonService],()=>{
  let injector = Injector.resolveAndCreate([PERSON_SERVICE_PROVIDERS]);
  appInjector(injector);
}));

Ответ 5

Angular 2.0 окончательное решение:

Поскольку теперь мы определяем отдельный класс, который реализует CanActivate, этот класс может быть @Injectable, а в его конструкторе может быть предусмотрена другая зависимость в соответствии с ответ.