Is it possible to create a single directive that can handle both Structural and Attribute behaviors?

Trying to develop an Angular Directive that will handle various functionalities based on config input values

  1. Dynamically add elements to the DOM based on input values (similar to ngIf)
  2. Apply styling to rendered elements
  3. Add attribute properties such as disabled to elements

Based on my understanding of Angular, we can accomplish the first requirement using a Structural Directive. For the second and third requirements, we need to create an Attribute Directive. Below is the implementation for both directives

import { SomeService } from './some.service';
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({ selector: '[structuralBehaviour]' })
export class StructuralBehaviourDirective {

    constructor(private templateRef: TemplateRef<any>,
        private viewContainer: ViewContainerRef, private someService: SomeService) { }

    @Input() set structuralBehaviour(config: any) {

        // Handling the logic for adding template in DOM
        this.viewContainer.createEmbeddedView(this.templateRef);

   }
}

Here is the Attribute Directive

import { SomeService } from './some.service';
import { Directive, ElementRef, Input, Renderer } from '@angular/core';

@Directive({ selector: '[attributeBehaviour]' })
export class AttributeBehaviourDirective {

    constructor(private _renderer: Renderer, private _el: ElementRef,
    private someService: SomeService) { }

    @Input() set attributeBehaviour(config: any) {

        // Applying style visibility property to hidden
        this._el.nativeElement.style.visibility = 'hidden';

        // Adding disabled attribute 
        this._renderer.setElementProperty(this._el.nativeElement, 'disabled', true);

    }
}

Currently, I am using these directives as follows, which is working well

<button *structuralBehaviour="config" [attributeBehaviour]="config"
 class="btn btn-primary">Add</button> 

I'm exploring if it's possible to merge both directives into a single directive for ease of use, something like this

<button *singleBehaviour="config" class="btn btn-primary">Add</button> 

Answer №1

When you call this.viewContainer.createEmbeddedView
, it will provide you with an EmbeddedViewRef that includes the rootNodes. This can be used to define your desired behavior.

@Directive({ selector: '[singleBehaviour]' })
export class SingleBehaviourDirective {
  constructor(
    private templateRef: TemplateRef<any>,
    private _renderer: Renderer2,
    private viewContainer: ViewContainerRef) { }

  @Input() set singleBehaviour(config: any) {
    let view = this.viewContainer.createEmbeddedView(this.templateRef);
    let rootElem = view.rootNodes[0];
    if(rootElem) {
      rootElem.style.visibility = 'hidden';
      this._renderer.setProperty(rootElem, 'disabled', true);
    }
  }
}

Check out this Plunker Example

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

Step-by-step guide on activating a button only when all form fields are validated

My very first Angular 5 project. I've gone through resources like: https://angular.io/guide/form-validation and various search results I looked up, only to realize that they are all outdated. In my form, I have several input fields such as: <for ...

What is the best approach for transferring non-string objects between routes in Angular?

I am currently developing a custom file viewer. To achieve this, I have created a specialized component known as FileBrowserComponent that is specifically designed to be displayed when the route /files is accessed. When navigating, I include a query param ...

Issue with Angular 5 template: "AbstractControl type does not contain property 'length'"

While attempting to compile my Angular project using the command ng build --prod --output-path <my_destination_path>, I encountered a few errors like the following: ERROR in src/app/products/product-edit/product-edit.component.html(190,10): : Proper ...

Is there a method to define an 'internal' property within a TypeScript type?

I created a custom 'library' in Angular and TypeScript. This library is distributed as a *.ts package within other Angular workspaces. Within this library, I have an exported class that contains various properties. One specific property in thi ...

Unable to clear all checkboxes after deleting

In my application, there are 3 checkboxes along with a master checkbox that allows users to select or deselect all of them at once. Everything works fine with the master checkbox until I delete some rows from the table. After deleting data, I can check th ...

Strategies for splitting a component's general properties and accurately typing the outcomes

I am attempting to break down a custom type into its individual components: type CustomType<T extends React.ElementType> = React.ComponentPropsWithoutRef<T> & { aBunchOfProps: string; } The code appears as follows: const partitionProps = ...

Angular 14 captures typed form data as `<any>` instead of the actual data types

On the latest version of Angular (version 14), I'm experiencing issues with strictly typed reactive forms that are not functioning as expected. The form initialization takes place within the ngOnInit using the injected FormBuilder. public form!: For ...

What could be the reason my mat-form-field is not displaying the label?

I'm currently working on a project using Angular Material to build a web page. I am facing an issue with the mat-form-field component as the label is not displaying, and I can't figure out why. Any assistance would be greatly appreciated. Thank y ...

Building a filter for a union type in TypeScript: a step-by-step guide

Allow me to present an example to demonstrate my current objective. const v1: { type: "S"; payload: string } = { type: "S", payload: "test" }; const v2: { type: "N"; payload: number } = { type: "N", payload: 123 }; type Actions = typeof v1 | typeof v2; ...

Adding a ng-select field when a button is clicked

In my template, I am using ng2-select to allow users to select items. There is a button called "Add" that, when clicked, should display another select field with a list of different item categories. However, the current version of my code does not achieve ...

Exploring Angular: Adding elements to formArray and tracking form value modifications

I am currently working on a Form that utilizes a formArray : initForm() { this.mainForm = this.formBuilder.group({ foos: this.formBuilder.array([], [Validators.required]), }); getFoos(): FormArray { return this.mainForm.get(&apos ...

The ngx-datatable is designed to bind only to the final comparator

When utilizing templates with ngx-datatable-column and binding comparator functions, only the final bound comparator is applied to all sortable columns. For instance: <div class="m-333"> <button mat-raised-button color="primary" (click)="openP ...

Is the return type determined by the parameter type?

I need to create an interface that can handle different types of parameters from a third-party library, which will determine the return type. The return types could also be complex types or basic types like void or null. Here is a simple example demonstra ...

Detecting the presence of a session in Angular2 and nodejs using express

My server-side session creation is functioning properly, but I need to be able to hide certain elements in an Angular2 component template depending on whether the session exists. How can I check within my Angular2 component whether the server-created sessi ...

Error in Typescript: Unable to locate module with proper type declarations

Recently embarking on a new nodejs project with typescript, I utilized Typings (https://github.com/typings/typings) to install reference files for node v4.x and express v4.x. Outlined in my setup are the following versions: Node - v4.2.6 Typescript - v1 ...

Enhance your Next.js routing by appending to a slug/url using the <Link> component

In my Next.js project, I have organized my files in a folder-based structure like this: /dashboard/[appid]/users/[userid]/user_info.tsx When using href={"user_info"} with the built-in Next.js component on a user page, I expect the URL to dynamic ...

npm-install fails to automatically install sub-dependencies

I'm currently working on an Angular 4 project that has specific dependencies. The project is functioning properly as it is. Now, my goal is to utilize this project in another project. I've added the original project to the package.json file (und ...

All components load successfully except for the worker in Webpack

I've been working on configuring webpack to bundle my react project. I successfully set up the webpack_public_path variable and all modules are loading correctly, except for the worker. const path = require('path'); const MonacoWebpackPlugi ...

Encountering a problem with the 'string' parameter when using TypeScript

I keep encountering the following error message: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ barkingRoadProject: string[]; }'. No index signature with a paramet ...

Accessing the value of an object nested within another object in Angular

I have encountered numerous similar topics, but after going through all of them, I still cannot pinpoint what I am doing incorrectly. The data I retrieve is from DEXIE (indexedDB) where my record is stored in the following format: async addRequestToLocalD ...