Angular 4: Leveraging a directive as a universal constant

I am looking to develop a directive that allows me to utilize a template variable in order to access a global variable, much like $rootScope in Angular.JS. The goal is to avoid having to inject a service into every component where I need access to the variable.

Here's an example:

@Directive({
    selector: '[app]',
    exportAs: 'app'
})
export class AppDirective {
    isLoggedIn: boolean = false;

    constructor() {
        // Code to initialize 'this.ready' will go here...
    }
}

The intention is to use the code above in my template as follows:

<div #app>
    <div *ngIf="app.isLoggedIn">...</div>
</div>

Is it possible to achieve something like this?

Answer №1

Instead of using ngIf, consider implementing a directive for more efficient code. By injecting your service into the directive, you can maintain DRY (Don't Repeat Yourself) principles and keep markup minimal in your components.

You can create a directive like this:

@Directive({
  selector: '[showIfLoggedIn]'
})
export class ShowIfLoggedInDirective implements OnInit {
  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainerRef: ViewContainerRef
  ) { }

  ngOnInit() {
    var isLoggedIn = false; // Use service here and inject into the constructor.
    if(isLoggedIn) {
        this.viewContainerRef.createEmbeddedView(this.templateRef);
      } else {
        this.viewContainerRef.clear();
      }
  }
}

To use it:

<h2 *showIfLoggedIn> I am logged in </h2>

To apply a class dynamically:

@Directive({
  selector : '[applyClassIfLoggedIn]'
})

export class ApplyClassIfLoggedIn implements OnInit {
  @Input('applyClassIfLoggedIn') className;
  constructor(
    private ele: ElementRef,
    private renderer: Renderer2
  ) { }


  ngOnInit() {
    var isLoggedIn = true; // Use service here.
    if(isLoggedIn) {
        this.renderer.addClass(this.ele.nativeElement, this.className);
    }

  }
}

Then:

<h2 applyClassIfLoggedIn='logged-in'>Red if logged in </h2>

Check out the Plunkr example here

Answer №2

There are two main approaches to achieve this task, both requiring the injection of a common service into the components that need it. By implementing these methods, you can minimize the need to modify the component code beyond the constructor and template sections.

Method 1: Direct Service Call from Template

application.component.ts

import {SecurityService} from './security.service';
@Component({
    selector: '[App]',
    template: `<div *ngIf="securityService.isLoggedIn">Logged in!</div>`
})
export class ApplicationComponent {
  constructor(public securityService: SecurityService){ }
}

Method 2: Using a Shared Abstract Class

security-context.component.ts

import {SecurityService} from './security.service';
export abstract class SecurityContextComponent {
  constructor(protected securityService: SecurityService){}

  get isLoggedIn(): boolean{
    return this.securityService.isLoggedIn;
  }
}

application.component.ts

import {SecurityContextComponent} from './security-context.component';
import {SecurityService} from './security.service';

@Component({
    selector: '[App]',
    template: `<div *ngIf="isLoggedIn">Logged in!</div>`
})
export class ApplicationComponent implements SecurityContextComponent {
  constructor(securityService: SecurityService){
    super(securityService);
  }
}

Answer №3

To determine if a random value returns a boolean based on the global variable, you can use the pipe method.

<div #app>
    <div *ngIf="'randomstring' | auth">...</div>
</div>

In this scenario, auth is associated with an AuthPipe that outputs either true or false depending on the global variable.

Simply injecting a dependency into the pipe should suffice for this purpose.

While it may not be the most elegant solution, using pipes within templates is effective in achieving the desired outcome.

Answer №4

Here is an interesting approach to consider:

If you are open to utilizing your template within your .ts file, you can implement something similar to the following (taken from the provided post):

Start by creating a global class:

export class Globals {
    isLoggedIn = true;
}

Then incorporate this into your component:

import { Globals } from './globals';

@Component({
    selector: 'my-app',
    template: `<h1>My Component {{globals.isLoggedIn}}<h1/>`
})
export class AppComponent {
    constructor(){
    }
}

The key lies in using backticks (`) which enables the execution of {{globals.var}}

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

Encountering complications when importing TypeScript declarations

I am facing a problem with importing declarations from an extended file (I am utilizing this typing). As per the example, I have included this code in my project: import * as SockJS from 'sockjs-client'; import BaseEvent = __SockJSClient.BaseEve ...

Ways to incorporate only essential UI elements in @angular/material

In the process of creating my Angular application, I am looking to streamline its size. Currently, my app relies on Angular Material, but upon inspecting the node_modules folder, I realized that there are unused UI components such as autocomplete and check ...

Experimenting with Nuxtjs application using AVA and TypeScript

I'm in the process of developing a Nuxt application using TypeScript and intend to conduct unit testing with AVA. Nonetheless, upon attempting to run a test, I encounter the following error message: ✖ No test files were found The @nuxt/typescrip ...

What is the best way to test chained function calls using sinon?

Here is the code I am currently testing: obj.getTimeSent().getTime(); In this snippet, obj.getTimeSent() returns a Date object, followed by calling the getTime() method on that Date. My attempt to stub this functionality looked like this: const timeStu ...

PhpStorm flawlessly detects ES7 type hinting errors

For my project, I have implemented TypeScript. While JavaScript's array includes() function has been valid since ECMA6, setting the lib parameter in tsconfig to "es6" results in a non-fatal error being thrown in the browser console when using the foll ...

Interference with ElementClickInterceptedException in Selenium is caused by the presence of a WebPack iframe within an Angular application, despite implementing WebDriverWait

Everything was going smoothly with my automation code until suddenly, an ElementClickIntercepted exception started occurring when trying to click the "Sign In" button on the login screen: public class LoginPage { private readonly IWebDriver driver; ...

Is there a way to make an angular component reuse itself within its own code?

I am dealing with a parent and child component scenario where I need to pass data from the parent component to the child component. The aim is to display parentData.name in the child component when parentData.isFolder===false, and if parentData.isFolder=== ...

What is the process for unit testing the 'navigate' function in Angular that includes query parameters?

Below is the code snippet from my component: editThis(id) { this.router.navigate(['/categories/edit'], { queryParams: { id: id } }); } The following represents my unit test-case: fit('should call navigate with correct parameters&ap ...

Please exclude any files with the name npm-debug.log.XXXXXX in the .gitignore file

Is there a way to exclude this file from the repository using .gitignore? https://i.stack.imgur.com/mK84P.png I am currently working on Gitlab. I have attempted the following: https://i.stack.imgur.com/2kN21.png Appreciate any help in advance ...

Is there a way to programmatically add a timestamp to a form in Angular6?

Is there a way to automatically populate new forms with the current datetime value? this.editForm.patchValue({ id: chatRoom.id, creationDate: chatRoom.creationDate != null ? chatRoom.creationDate.format(DATE_TIME_FORMAT) : null, roo ...

The Angular filter feature operates on individual columns instead of filtering all columns simultaneously

Introduction I am currently working on implementing a feature in my Angular application where the column filter continuously updates the results based on the selected filters. The issue I'm facing is that when I select a filter in one column, it corr ...

Triggering an event within a component to execute a specific function in another component

I am working on a component that includes multiple routes such as home, app, and navbar. My goal is to have the encrementcalc() function execute when the navbar button is pressed. I attempted to use the event emitter but was unsuccessful. Can someone prov ...

Angular 8 - Utilizing External URL Routing

After creating a route that generates a token, I encountered an error when trying to retrieve the token from the URL: if (!this.session.token) { let urlToken= 'https://www.url-system.com.br//auth&redirect_uri=http://8000/api/res-token'; let r ...

Issue with triggering angular function multiple times in certain conditions

Issue: Experiencing difficulties with Angular directive as it is being called multiple times, resulting in incorrect transaction outcomes and multiple entries on the Console screen. Desired Outcome: Ensure that the function executes only once. Sample cod ...

What steps can I take to address the issue of missing modules in an Angular application?

I am facing an issue with my Angular application where I am using two local libraries. Despite having all dependencies declared and imported correctly, the build process continues to throw errors related to missing modules. To give you a better picture of ...

When attempting to assign a variable in my ngModel, what issue could be causing a problem?

I am facing an issue while trying to implement ngModel in my code. The code is not executing properly and an error is being displayed. Below is the code snippet: contact-form.component.html: <div class="container"> <form> <div class ...

Leveraging the @Input decorator to send external data into the Angular component

In my Ionic app, I am utilizing an Angular component. Within this component, there is a variable called headerText that is supposed to be initialized from the page where the component is being used. The issue arises when the headerText variable is always ...

Can you provide information on the type signature of the `onChange` event for the MUI DatePicker?

I am utilizing an instance of the MUI DatePicker along with a MomentAdapter: import *, {useState} as React from 'react'; import TextField from '@mui/material/TextField'; import { AdapterMoment } from '@mui/x-date-pickers/AdapterMom ...

Guide on utilizing external namespaces to define types in TypeScript and TSX

In my current project, I am working with scripts from Google and Facebook (as well as other external scripts like Intercom) in TypeScript by loading them through a script tag. However, I have encountered issues with most of them because I do not have acces ...

Ways to showcase my select/option in Angular 14?

My select input is not displaying and I'm struggling to understand why. Despite seeing it in the inspector, it remains hidden... I initially attempted to retrieve data from my service, which failed. Then, I experimented with placing static data direc ...