Событие Angular2 для обнаружения изменений в директиве

#angular #typescript #angular2-directives

#angular #typescript #angular2-директивы

Вопрос:

У меня есть AuthService, который входит / выходит из системы, проверяет, зарегистрирован ли пользователь, и работает с angular2-jwt ним (например, использует tokenNotExpired() ).

Я создал модуль только для этой службы, чтобы использовать его как одноэлементный.

Теперь я проверяю, вошел ли пользователь в систему, например, с помощью этого:

 <p *ngIf="authService.authenticated()">Text</p>
  

Который работает, как и ожидалось.

Теперь я хочу добиться того, чтобы обернуть это *ngIf в собственную директиву, чтобы компоненты, проверяющие, вошел ли пользователь в систему, не должны вводить AuthService.

В основном так:

 <p *authenticated>Text</p>
  

Я создал аутентифицированную директиву следующим образом:

 @Directive({selector: "[authenticated]"})
export class AuthenticatedDirective {

    constructor(private templateRef: TemplateRef<any>,
                private viewContainer: ViewContainerRef,
                private auth: AuthService) {
    }

    @Input() set authenticated(condition: boolean) {
        if (this.auth.authenticated()) {
            console.log("IsLoggedIn");
            this.viewContainer.createEmbeddedView(this.templateRef);
        } else {
            console.log("NotLoggedIn");
            this.viewContainer.clear();
        }
    }

}
  

По сути, это директива *ngIf, только она не использует параметр.

Проблема в том, что оно вызывается только при загрузке сайта, оно не проверяет this.auth.authenticated() регулярно, истек ли срок действия токена.

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

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

Итак, в основном мой вопрос заключается в том, как я могу прослушать событие обнаружения изменений или есть лучшее решение для этого *ngIf="authService.authenticated()" ?

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

Обновить:

С комментарием от @Chrillewoodz я наконец-то вспомнил хуки жизненного цикла, особенно упомянутую проверку.

Мое текущее решение для директивы теперь таково:

 @Directive({selector: "[authenticated]"})
export class AuthenticatedDirective implements DoCheck {

    private isAuthenticated = false;

    constructor(private templateRef: TemplateRef<any>,
                private viewContainer: ViewContainerRef,
                private auth: AuthService) {
    }


    ngDoCheck() {
        if (this.isAuthenticated !== this.auth.authenticated()) {
            this.isAuthenticated = this.auth.authenticated();
            if (this.auth.authenticated()) {
                console.log("IsLoggedIn");
                this.viewContainer.createEmbeddedView(this.templateRef);
            } else {
                console.log("NotLoggedIn");
                this.viewContainer.clear();
            }
        }
    }

}
  

Комментарии:

1. DoCheck вероятно, это ваше решение.

Ответ №1:

Я думаю, что в зависимости от того, как написана ваша директива, вам нужно будет использовать вашу директиву следующим образом

 <p *authenticated="isAuthenticated">Text</p>
  

Где isAuthenticated возвращает true или false (независимо от того, прошли ли вы проверку подлинности)

Я думаю, что вместо опроса authService.authenticated() вам следует добавить наблюдаемый authService объект, о котором вы уведомляете.

 @Directive({selector: "[authenticated]"})
export class AuthenticatedDirective {

    constructor(private templateRef: TemplateRef<any>,
                private viewContainer: ViewContainerRef,
                private auth: AuthService) {
        auth.isAuthenticated.subscribe(authenticated => {
          if (authenticated()) {
              console.log("IsLoggedIn");
              this.viewContainer.createEmbeddedView(this.templateRef);
          } else {
              console.log("NotLoggedIn");
              this.viewContainer.clear();
          }
        });
    }
}
  

https://angular.io/docs/ts/latest/cookbook/component-communication.html показывает несколько хороших примеров того, как создавать сервисы с помощью наблюдаемых объектов.

Комментарии:

1. Спасибо за (еще раз) быстрый ответ. Проверка в комментарии к моему вопросу пока работает. В этом случае я уже пытался работать с наблюдаемыми / подписками, тогда это не сработало для моего случая, возможно, я сделал что-то не так, но я предполагаю, что angular на самом деле не понял, что директива изменилась. Считаете ли вы, что подписка — лучшее решение, чем использование перехвата doCheck?

2. Определенно. ngDoCheck может вызываться сотни или тысячи раз. Вы можете себе представить, что это довольно неэффективно для чего-то, что обычно меняется менее 10 раз в течение жизненного цикла приложения. С наблюдаемым вообще ничего не вызывается, пока значение не изменится.

3. Конечно, имеет смысл …. «трансляция» намного дешевле, чем опрос проверки. Сегодня утром я попробовал подход astronaut / mission (хотя и из моей головы) с объектами, он не обновил представление. Я попробую еще раз завтра и прокомментирую здесь или отредактирую свой вопрос, сработало ли это или нет.

4. Возможно, стоит также задать новый вопрос.

5. Хорошо, заставил его работать с наблюдаемым, я настраиваю интервал с помощью (setInterval()), который проверяет каждые 10 секунд, истек ли срок действия токена, если это так, он передает currentstate директивам. Он также транслируется после входа / выхода из системы. Это еще не идеально, но в основном это работает. Спасибо за ваш вклад.