Detecting changes in directives in Angular2 using events

My AuthService manages login/logout functionality, checks user authentication status, and utilizes angular2-jwt (specifically uses tokenNotExpired()).

To ensure the AuthService functions as a singleton, I created a Module dedicated to this service.

Currently, I check if a user is logged in using the following approach:

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

This method works as intended.

However, I aim to encapsulate this logic within its own directive so that components checking for user authentication status do not need to inject the AuthService.

The desired outcome is something like this:

<p *authenticated>Text</p>

The directive I created for this purpose looks like this:

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

}

This directive essentially replicates the functionality of *ngIf but without any parameters.

The issue I am facing is that the directive only runs when the site loads and does not continuously monitor this.auth.authenticated() to determine if the token has expired.

Simply triggering change detection does not have any effect if the directive is not listening for it. Manually triggering it after, for example, a logout does not produce the desired result either.

I understand that I can listen for events within the directive using host or HostListeners, but I cannot find an event related to change detection that would allow me to update the directive.

In essence, my question is how can I listen for the change detection event or is there a better approach to wrapping

*ngIf="authService.authenticated()"
?

Thank you in advance.

UPDATE:

Following the suggestion from @Chrillewoodz, I recalled lifecycle hooks, specifically the DoCheck hook.

The updated solution for my directive now looks like this:

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

}

Answer №1

It seems that the best approach for using your directive is to implement it in the following way:

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

The function isAuthenticated should return either true or false, indicating whether the user is authenticated.

Instead of continuously checking authService.isAuthenticated(), consider adding an observable to authService that alerts on authentication status changes.

@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("User is Logged In");
              this.viewContainer.createEmbeddedView(this.templateRef);
          } else {
              console.log("User is Not Logged In");
              this.viewContainer.clear();
          }
        });
    }
}

You can find more examples and information on creating services with observables at https://angular.io/docs/ts/latest/cookbook/component-communication.html.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to retrieve an object of type T from a collection of classes that extend a common base type in Typescript

In my current project, I have a class named Foo that is responsible for holding a list of items. These items all inherit from a base type called IBar. The list can potentially have any number of items. One challenge I am facing is creating a get method in ...

Header remains fixed when scrolling

Is there a way to make the header of a Bootstrap table fixed when scrolling, while also adjusting the width of each column based on the content within it? I want the column headers to match the width of the row with the most text. Setting the position of t ...

Is it possible to implement a redirect in Angular's Resolve Navigation Guard when an error is encountered from a resolved promise?

I have integrated Angularfire into my Angular project and am utilizing the authentication feature. Everything is functioning properly, however, my Resolve Navigation Guard is preventing the activation of the component in case of an error during the resolve ...

The function encounters an undefined array when called, despite the array being defined outside of the

Encountering an issue where an array I initiate is suddenly undefined within a function. Here is the code snippet: import { Component, OnInit } from '@angular/core'; import { text } from '@angular/core/src/render3'; import{SheetModel} ...

Steps for setting up Protractor Cucumber Report with TypeScript and screenshots:

I've searched for many tutorials on setting up Protractor with Cucumber reports and screenshots in TypeScript, but have had no luck. Can you provide assistance in configuring this? ...

Using TypeScript, you can pass an object property name as a function argument while ensuring the type is

How can I define a type in a function argument that corresponds to one of the object properties with the same type? For instance, if I have an object: type Article = { name: string; quantity: number; priceNet: number; priceGross: number; }; and I ...

How can you tell if Video Players like YouTube and Vimeo are blocked by a 403 Forbidden error, and show an image in their place instead?

We are managing a website where we showcase a prominent video stage for all visitors. However, there is a particular client that prohibits all videos with a 403 forbidden status on their devices and we are looking to substitute an image in place of the blo ...

Tips for creating a typescript typeguard function for function types

export const isFunction = (obj: unknown): obj is Function => obj instanceof Function; export const isString = (obj: unknown): obj is string => Object.prototype.toString.call(obj) === "[object String]"; I need to create an isFunction method ...

Can [] be considered a valid type in Typescript language?

I've come across this function: function stringToArray(s: string|[]): [] { return typeof s === 'string' ? JSON.parse(s.replace(/'/g, '"')) : s; } This function is functioning as expected without any type warnings. Bu ...

Creating Instances of Variables Within a Class

Currently, I am working on a project using Ionic and Angular. I have come across various ways of instantiating variables and I'm unsure about the implications of each method. Here are three scenarios that confuse me: export class someClass { myVaria ...

ENTER DATE VALUE INTO ANGULAR

SERVICE.TS addP(nome: string, cognome: string, anno_n: string): Observable<any> { return this.http.post<Partecipanti>(this.partecipantiUrl, { nome: nome, cognome: cognome, anno_n: anno_n }, this.httpOptions).pip ...

The "ng2-CKEditor" package is experiencing compatibility issues with TypeScript in Angular 2

Currently, I am in the process of setting up CKEditor in my angular2 application. My backend platform is node.js and for this purpose, I am utilizing the ng2-CKEditor npm module. Below, you can find snippets from respective files. index.html:: <html& ...

When another page is refreshed, Angular routing redirects back to the home page

Within my application, there is a homepage that appears after the user logs in, along with some other pages. However, I've encountered an issue where when I navigate to one of these other pages and then refresh the page, it redirects me back to the ho ...

Retrieving a global variable within a nested function

I am encountering a scope issue with my nested function while trying to pass two global variables. I need some help as I keep getting this error when running the code: Uncaught (in promise): TypeError: Cannot read properties of undefined (reading 'use ...

How can hover effects be incorporated within an inline style?

I utilized the Button component from ant design and adjusted its color using style. Now, I am looking to add a hover color effect to this Button. How can I achieve this? export default class NavBar extends React.Component{ render(){ return( ...

"Encountering the error of 'require is not defined' in an Electron-React-Webpack-Typescript application when utilizing

When I add these lines to /src/renderer.ts in an Electron-React-Webpack-Typescript app: ipcRenderer.on('messageFromMain', (event, message) => { console.log(`This is the message from the second window sent via main: ${message}`); }); I encou ...

Finding the device ID of both a computer and browser in Angular 5: How can it be done?

https://i.sstatic.net/bnUK6.pngCurrently, I am actively involved in the development of a web banking application using Angular 5. One of the tasks at hand is to identify the device ID of a computer and retrieve the browser name. I attempted to tackle this ...

Tips for emphasizing active tabs in Angular 6

**I have everything displaying perfectly, but I am wondering how to highlight the active tab without using any third-party components. Any assistance would be greatly appreciated. Thank you.** <ul class="tabs"> <li [ngClass]=" {'active-tab ...

How do I add a new module to an existing one using Angular-CLI?

After generating modules: $ ng generate module myTestModule installing module create src/app/my-test-module/my-test-module.module.ts $ ng generate module myTestModule2 installing module create src/app/my-test-module2/my-test-module2.module.ts I ha ...

Utilize dynamically generated form fields to upload multiple files at once

Currently, as I delve into learning the MEAN stack, I am encountering difficulties with file uploads. Specifically, within a company form: this.companyForm = this.fb.group({ trucks: this.fb.array([]), ... }); The 'trucks' field i ...