【问题标题】:Angular2 Event for Change detection for Directive用于指令更改检测的 Angular2 事件
【发布时间】:2017-02-13 19:50:07
【问题描述】:

我有一个登录/注销的 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() 以查看令牌是否已过期。

如果指令不监听它,触发更改检测当然不会做任何事情,因此手动触发(例如,在注销后)它不起作用。

我知道您可以“监听”(使用主机或 HostListeners)指令中的事件,但我找不到用于更改检测的事件,我可以使用它触发指令“更新”。

所以基本上我的问题是,我该如何收听更改检测事件,或者是否有更好的解决方案来包装这个*ngIf="authService.authenticated()"

提前致谢。

更新:

随着@Chrillewoodz 的评论,我终于想起了生命周期钩子,尤其是提到的 DoCheck。

我目前对该指令的解决方案是这样的:

@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();
            }
        }
    }

}

【问题讨论】:

  • DoCheck 可能是您的解决方案。

标签: angular typescript angular2-directives


【解决方案1】:

我认为您的指令的编写方式需要使用您的指令,例如

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

其中isAuthenticated 返回truefalse(无论您是否经过身份验证)

我认为,与其轮询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 展示了一些关于如何使用可观察对象创建服务的不错示例。

【讨论】:

  • 感谢(再次)快速回答。 DoCheck 在我的问题的评论中现在有效。在这种情况下,我已经尝试使用 observables/subscriptions,当时它对我的情况不起作用,也许我做错了什么,但我猜 angular 并没有真正理解指令发生了变化。您认为订阅是比使用 DoCheck 挂钩更好的解决方案吗?
  • 当然。 ngDoCheck 可以被调用数百或数千次。您可以想象,这对于在应用程序生命周期中通常更改少于 10 次的东西来说是非常低效的。使用 observable 在值发生变化之前,什么都不会被调用。
  • 当然有意义....“广播”比轮询支票便宜得多。今天早上我尝试了宇航员/任务方法(尽管是从我的脑海中),它没有更新视图。明天我会再试一次并在这里评论或编辑我的问题,如果它有效与否。
  • 可能也值得提出一个新问题。
  • 好的,让它与 Observable 一起工作,我用 (setInterval()) 设置了一个 Intervall,它每 10 秒检查一次令牌是否过期,如果是,它将当前状态广播到指令。它还在登录/注销后广播。它还不完美,但基本上可以工作。感谢您的意见。
猜你喜欢
  • 2016-07-07
  • 2016-07-13
  • 2016-07-05
  • 1970-01-01
  • 1970-01-01
  • 2017-10-03
  • 2017-06-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多