2016-10-05 3 views
2

Ich habe einen AuthService, der sich anmeldet, prüft, ob der Benutzer angemeldet ist und mit angular2-jwt arbeitet (zum Beispiel tokenNotExpired()).Angular2 Event for Change Erkennung für Richtlinie

Ich habe ein Modul nur für diesen Dienst erstellt, um es als Singleton zu verwenden.

Jetzt überprüfe ich, ob der Benutzer in zum Beispiel mit diesem angemeldet ist:

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

Welche wie erwartet funktioniert.

Nun, was ich erreichen möchte, ist diese *ngIf in eine eigene Direktive zu wickeln, so dass die Komponenten, die überprüfen, ob der Benutzer angemeldet ist, den AuthService nicht injizieren müssen.

Im Grunde wie folgt aus:

<p *authenticated>Text</p> 

ich die authentifizierte Richtlinie wie folgt geschaffen:

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

} 

Es ist im Grunde die * ngIf Richtlinie, nur, dass es nicht den Parameter nicht verwendet.

Das Problem ist, dass es nur aufgerufen wird, wenn die Website geladen wird, überprüft this.auth.authenticated() nicht regelmäßig, um zu sehen, ob das Token abgelaufen ist.

Das Auslösen der Änderungserkennung macht natürlich nichts, wenn die Direktive nicht darauf hört, also manuell auslösen (zB nach einem Logout) funktioniert es nicht.

Ich weiß, dass Sie (mit Host oder HostListeners) für Ereignisse in der Direktive "hören" können, aber ich kann das Ereignis für die Change-Erkennung nicht finden, mit dem ich die Richtlinie "update" auslösen könnte.

Also im Grunde ist meine Frage, wie kann ich auf die Change Detection Event zu hören oder gibt es eine bessere Lösung zum Einwickeln dieser *ngIf="authService.authenticated()"?

Vielen Dank im Voraus.

UPDATE:

Mit dem Kommentar von @Chrillewoodz ich schließlich Lifecycle Haken erinnert, vor allem die erwähnten DoCheck.

Meine aktuelle Lösung für die Richtlinie ist jetzt das:

@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' ist wahrscheinlich Ihre Lösung. – Chrillewoodz

+0

Danke, habe nicht an den Lebenszyklus-Haken gedacht .... Es funktioniert natürlich. – derpawe

Antwort

4

Ich denke, die Art und Weise Ihre Richtlinie Sie Ihre Richtlinie wie verwenden müssten geschrieben

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

Wo isAuthenticated kehrt true oder false (ob Sie authentifiziert sind)

Ich denke, anstelle der Abfrage authService.authenticated() sollten Sie eine Observable zu authService hinzufügen, die darüber benachrichtigt.

@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 zeigt einige schöne Beispiele darüber, wie Dienste mit Observablen zu erstellen.

+0

Danke für die (wieder) schnelle Antwort. DoCheck im Kommentar meiner Frage funktioniert für jetzt. In diesem Fall habe ich bereits versucht, mit Observablen/Subskriptionen zu arbeiten, es hat damals für meinen Fall nicht funktioniert, vielleicht habe ich etwas falsch gemacht, aber ich glaube, angular hat nicht wirklich verstanden, dass die Direktive geändert wurde. Glauben Sie, dass ein Abonnement eine bessere Lösung ist als die Verwendung des DoCheck-Hooks? – derpawe

+0

Definitiv. 'ngDoCheck' kann hunderte oder tausende Male aufgerufen werden. Sie können sich vorstellen, dass dies für etwas, das sich normalerweise während eines Anwendungslebenszyklus weniger als zehn Mal ändert, ziemlich ineffizient ist. Bei einem Observablen wird gar nichts aufgerufen, bis sich der Wert ändert. –

+1

Macht natürlich Sinn .... "Broadcasting" ist viel weniger teuer als das Abfragen des Schecks. Ich versuchte den Astronaut/Mission-Ansatz (obwohl von meinem Kopf) mit den Themen heute Morgen, es aktualisiert nicht die Ansicht. Ich werde es morgen nochmal versuchen und hier kommentieren oder meine Frage bearbeiten, ob es funktioniert oder nicht. – derpawe