Obtaining a dependency directly from the Injector within a directive

I am currently working on developing a versatile directive that can take a class type for validating rules. Depending on the rule specified in the class, the directive will either display or hide an element.

This is my progress so far.

Check out the PLUNKER demo here

Custom-Directive.js

@Directive({
  selector: '[customDirective]'
})
export class CustomDirective {
  constructor(private _viewContainer: ViewContainerRef,
    private _template: TemplateRef<Object>) 
  { }

  @Input() set customDirective(rule: string) {
    // The rule class type will be provided as a string
    // How do I utilize the string token to fetch dependencies from the injector?
    // Currently hardcoding it
    // Will the injector create a new instance or pass on an existing one from parent?
    let injector = ReflectiveInjector.resolveAndCreate([AdminOnly]);
    let adminOnly : IRule = injector.get(AdminOnly);
    let show = adminOnly.shouldShowElement();
    show ? this.showItem() : this.hideItem();
  }
  private showItem() {
    this._viewContainer.createEmbeddedView(this._template);
  }

  private hideItem() {
    this._viewContainer.clear();
  }
}


app-component.ts

@Component({
  selector: 'my-app',
  template: `
    <div *customDirective="'AdminOnly'">
      <h2>Hello {{name}}</h2>
    </div>
  `,
})
export class App {
  name:string;
  constructor() {
    this.name = 'Angular2'
  }
}

However, I am facing two challenges:

  1. I keep encountering the error No Provider for AuthService
  2. I'm unsure about how to retrieve dependencies from the Injector using the class name as a string rather than its type

I would greatly appreciate any suggestions or feedback on whether my approach is correct or if there are errors in my implementation.

Answer №1

Make sure to provide the parent injector like

export class MyIfDirective {
  constructor(private injector:Injector, private _viewContainer: ViewContainerRef,
    private _template: TemplateRef<Object>) 
  { }

  @Input() set myIf(rule: string) {
    let resolvedProviders = ReflectiveInjector.resolve([AdminOnly]);
    let childInjector = ReflectiveInjector.fromResolvedProviders(resolvedProviders, this.injector);

    let adminOnly : IRule = childInjector.get(AdminOnly);
    let show = adminOnly.shouldShowElement();
    show ? this.showItem() : this.hideItem();
  }
  private showItem() {
    this._viewContainer.createEmbeddedView(this._template);
  }

  private hideItem() {
    this._viewContainer.clear();
  }
}

For more information check out Inject service with ReflectiveInjector without specifying all classes in the dependency tree

Answer №2

Just a quick update for using Angular version 10 and above:

  • When working with your service:
  @Injectable({
    providedIn: 'any'
  })
  export class AdminOnly { ... }
  • Incorporate the following code in your directive or pure function, ...:
 import { Injector } from '@angular/core';

 ...
 const injector: Injector = Injector.create({
   providers: [{provide: AdminOnly, deps: []}]
 });
 const adminOnly: AdminOnly = injector.get(AdminOnly);

 let show = adminOnly.shouldShowElement();
 ...

Learn more

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

What is the best way to handle errors generated by my jsdom.jqueryify callback function?

When running this code in node.js, the output is a stack trace of an error that occurs on line 9. Surprisingly, the error on line 7 seems to be 'absorbed' by Node. Even when wrapped in a try/catch statement, the detailed stack trace output is not ...

Dispatch prop within useEffect

App.js -> <Lobbies inGame={inGame} setLobby={setLobby} userName={userName} userKey={userKey}/> Lobbies.js -> import React, { useState, useEffect } from 'react'; import firebase from 'firebase'; const Lobby = ({userKey, ...

React - dynamically injecting external logic during execution

My goal is to modularize my React application by loading additional logic (such as containers/components) dynamically from an external .js file during runtime. For instance, I want to be able to introduce a new tab with completely different functionality o ...

Leveraging external JavaScript libraries in Angular 2

Having some trouble setting up this slider in my angular2 project, especially when it comes to using it with typescript. https://jsfiddle.net/opsz/shq73nyu/ <!DOCTYPE html> <html class=''> <head> <script src='ht ...

Using the native functionality, submitting a razor form with JQuery AJAX in MVC6

Is there a specific method to submit a form using jQuery AJAX in MVC6 while still utilizing the Auto Binding functionality of ASP.NET MVC? In previous versions of MVC, one could use jquery.unobtrusive-ajax and simply utilize @using (Ajax.BeginForm("SaveDa ...

Utilizing React forwardRef with a functional component

Looking at my code, I have defined an interface as follows: export interface INTERFACE1{ name?: string; label?: string; } Additionally, there is a function component implemented like this: export function FUNCTION1({ name, label }: INTERFACE1) { ...

Console log showing no response from AJAX request

For my group project, I've been working on setting up an API to display a response in the console log. After troubleshooting and fixing errors, I am still not seeing any response when I click submit. JavaScript var zipcode = ""; function localMovie ...

Using Angular to make an API call within a JavaScript function

I am facing an issue when trying to call an API in a JavaScript function as shown below. The injected services (subService) and defined variables (formData) are not recognized in the JavaScript function, resulting in an error of undefined addSub. How can I ...

When you use map to transform the value, Observable will consistently return as undefined

Can anyone help me figure out why, when I transform the observable, it returns undefined in the console log even though there are assigned values? HTTP Request getLibraryCardPeople(bookName: String): Observable<people[]> { return this.http.get<Li ...

Creating a Welcome Page for my React Application with IndexRoute

I am in the process of setting up a landing page that will then redirect to my main home page using React. I have created a component for the landing page named Splash. I am attempting to utilize IndexRoute to make sure my app initially displays Splash as ...

The preselected value in an AngularJS select box is set to static HTML by

In my HTML, I have a select tag that I am populating using ng-repeat. <td> <select ng-model="item.data.region" style="margin-bottom: 2px;"> <option ng-repeat="region in vm.regions track by $index" value="{{region}}">{{region} ...

What is the process for building .ts components within a Vue application?

Looking to update an old project that currently uses the 'av-ts' plugin and vue-ts-loader to compile .ts files as Vue components. The project is running on Vue 2.4.2, but I want to upgrade it to version 2.6.14. However, since 'vue-ts-loader& ...

How to assign ngModel to a nested component in Angular?

If I have a component called InputComponent, which implements the ControlValueAccessor interface. Now, another component named AnotherComponent uses the InputComponent like this: <my-input [(ngModel)]="text"></my-input> While testing AnotherC ...

Is it considered fundamentally inappropriate to call $scope.$digest within $scope.$on?

I recently inherited some AngularJS code, and my knowledge of both the codebase and Angular itself is limited. Within the code I inherited, there are instances where $scope.$digest is being called inside a $scope.$on method within a controller. Here's ...

Locating every quadrilateral within a mesh

I'm currently using Three.js to load a mesh and I am attempting to texture each quad individually. At the moment, I am able to texture each face (triangle), but I am unsure of how to determine if the current triangle and the last triangle are part of ...

What is the datatype for an Angular FormControl when dealing with numbers?

Having an issue with Angular FormControl when using it for text and number inputs. Both inputs are being recorded as text even though one is supposed to be a number. var control = this._formBuilder.control(this.settings[input.property]); control.valueChan ...

The accuracy of real-time visitor numbers in Google Analytics is often unreliable

My website uses Google Analytics to track the page chat.php. The code snippet is correctly placed on the page according to the documentation. Within this page, there is a Flash object that connects users to an IRC chat room. Currently, there are 50 unique ...

Batch requesting in Typescript with web3 is an efficient way to improve

When attempting to send a batch request of transactions to my contract from web3, I encountered an issue with typing in the .request method. My contract's methods are defined as NonPayableTransactionObject<void> using Typechain, and it seems tha ...

Steps to show submenus upon hovering over the main menu items

I am trying to create a vertical menu with multiple levels using HTML and CSS. Here is the code I have written so far: <ul> <li>Level 1 menu <ul> <li>Level 2 item</li> <li>Level 2 item</li&g ...

Crafting a Visual Storybook with Express.js

I am currently working on developing a photo album app using MEVN. In this project, the value of req.body.ALBUM is used as the folder name and req.body.DESCRIPTION is designated for describing the content. The issue I have encountered so far is that whil ...