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
, а в его конструкторе может быть предусмотрена другая зависимость в соответствии с ответ.