Setting Angular @Input dynamically for external components

Utilizing PrimeNG components, I am implementing the disabled attribute on different input controls using a directive. Among them are the p-dropdown, p-listbox, and p-calendar PrimeNG controls. While the standard input, textarea, and select controls work smoothly, the PrimeNG controls have disable defined as @Input in the following manner:

private _disabled: boolean;

@Input() get disabled(): boolean {
    return this._disabled;
};

Here is a snippet of the directive:

/*
** Find all inputs and disable them.
*/
disableElements(el: ElementRef): void {
    const controls = el.nativeElement.querySelectorAll('input, select, textarea, p-dropdown, p-listbox, p-checkbox');
    controls.forEach((elmt: any) => {
        this.disableElement(elmt);
    });
}
/*
** Disable an input element.
*/
disableElement(elmt: any): void {
    if (elmt.localName.substr(0, 2) === 'p-') {
        this._renderer.setProperty(elmt, 'disabled', 'true');
    } else {
        if (!elmt.hasAttribute('disabled')) {
            this._renderer.setAttribute(elmt, 'disabled', 'true');
        }
    }
}

Hence, the question arises: how can I disable the PrimeNG third-party controls with an ElementRef.nativeElement? I am contemplating on a method to satisfy the disabled @Input property with respect to an element reference.

Answer №1

Instead of using a directive to disable controls programmatically, I recommend handling it with regular inputs. However, I can offer a solution for your specific situation: https://stackblitz.com/edit/angular-disable-prime-ng-elements

The solution may not be perfect, but it's a workaround if you prefer not to work with disabled inputs.

  1. To start, create a directive named
    PrimeNgComponentsChangeDetectorRefDirective
    to access a public version of primeng components' change detector and update their views. Manually include all the primeng components you want to manage, using the same selector to automatically match them.
@Directive({
  selector: 'p-checkbox, p-dropdown, p-listbox'
})
export class PrimeNgComponentsChangeDetectorRefDirective {
  public hostComponent: Checkbox | Dropdown | Listbox;

  constructor(
    public cdr: ChangeDetectorRef,
    @Optional() private checkbox: Checkbox,
    @Optional() private dropdown: Dropdown,
    @Optional() private listbox: Listbox
  ) {}

  ngAfterViewInit() {
    this.hostComponent = this.getHostComponent();
  }

  private getHostComponent() {
    return [this.checkbox, this.dropdown, this.listbox].find(
      component => !!component
    );
  }
}
  1. In your disabling directive, include the following properties and methods:
  @ContentChildren(PrimeNgComponentsChangeDetectorRefDirective)
  private componentsQuery: QueryList<
    PrimeNgComponentsChangeDetectorRefDirective
  >;

  disablePrimeNgComponents() {
    const components = this.componentsQuery.toArray();

    components.forEach(component => {
      component.hostComponent.disabled = true;
      component.cdr.detectChanges();
    });
  }

We manually trigger detectChanges because we programmatically changed the disabled property and Angular is unaware of this change.

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 recommended way to handle data upon retrieval from a Trino database?

My goal is to retrieve data from a Trino database. Upon sending my initial query to the database, I receive a NextURI. Subsequently, in a while loop, I check the NextURI to obtain portions of the data until the Trino connection completes sending the entire ...

How can you add a Git submodule without specifying a URL?

I am looking to integrate my Angular folder as a submodule into my primary directory. The Angular folder has already been initialized as a git repository. It is currently a local folder on my Windows machine with no URL. After successfully initializing gi ...

Angular application experiencing issues with opening snackbar notifications

I'm currently working on a user registration application in Angular. My goal is to notify the user upon successful account creation or if an error occurs. I've been attempting to use a snackbar for this purpose, but it's not working as expec ...

Angular Material Dropdown with Option to Add New Item

Currently, I am utilizing Angular material to create a select dropdown for Religion. However, the available options may not encompass all the religions practiced worldwide. In order to account for this limitation, I aim to incorporate an "other option" tha ...

What is the best way to invoke a method in a child component from its parent, before the child component has been rendered?

Within my application, I have a parent component and a child component responsible for adding and updating tiles using a pop-up component. The "Add" button is located in the parent component, while the update functionality is in the child component. When ...

Ways to determine the types of props received by a function when the arguments vary for each scenario?

I have a specialized component that handles the majority of tasks for a specific operation. This component needs to invoke the onSubmit function received through props, depending on the type of the calling component. Below is an example code snippet show ...

Setting up ng-bootstrap for your project

I'm currently in the process of trying to incorporate the ng-bootstrap package into my application. To ensure I have all the necessary packages, I've executed npm i and updated both the @angular/core and @angular/cli modules to their latest vers ...

Incorporating New Relic into an Angular Universal application running on Node.js

I am in the process of integrating newrelic into my node.js application, which is built with angular universal and bundled using webpack. The first line in main.server.aot.ts reads: const newrelic = require('newrelic'); In addition, I have inc ...

Tips for binding data to numerous dynamic controls

Implementing reactive forms in my Angular project allowed me to create a simple form for adding employee work hours and breaks. The challenge I encountered was the inability to bind data from break controls. In the .ts file export class AddAppointmentForm ...

The error message "Type 'null' cannot be assigned to type 'Element | DocumentFragment'" occurs when using Nextjs/React createPortal

I am completely new to typescript. Currently, I'm working on a project that has a lot of pre-configured react components in JavaScript files (.js). My task now is to convert everything to TypeScript (.tsx) without triggering any ESLint errors. Unfort ...

Exploring ways to display all filtered chips in Angular

As a new developer working on an existing codebase, my current task involves displaying all the chips inside a card when a specific chip is selected from the Chip List. However, I'm struggling to modify the code to achieve this functionality. Any help ...

Creating a conditional interface based on props in TypeScript: A step-by-step guide

What is the most effective way to implement conditional props in a component that can be either a view or a button based on certain props? Let's take a look at an example called CountdownButtonI: class CountDownButton extends Component<CountdownBut ...

The element of type 'OverridableComponent<LinkTypeMap<{}, "a">>' cannot be assigned to a 'ReactNode'

I'm currently working on a project where there's a component named ListItemTextStyle. Within that component, the prop type is defined as follows: import { LinkProps, ListItemButtonProps, } from '@mui/material'; type IProps = LinkP ...

Comparing numbers in Angular using Typescript

Hello! I'm encountering an issue with comparing two variables: console.log(simulation.population == 40000000); //true console.log(simulation.initialInfectedNumber == 5); //true console.log(simulation.population < simulation.initialInfectedNumber); ...

Showing the child component as undefined in the view

Within my Angular application, I encountered an issue involving a parent component named DepotSelectionComponent and its child component SiteDetailsComponent. The problem arises when an event called moreDetails is emitted to the parent component, triggerin ...

Guide to showcasing associated information in HTML using Angular 7

I am a beginner with Angular 7 and I am attempting to showcase a product's color on the HTML side using Angular 7 but have not been successful. Below are my tables; Product Id Name Color Id Name ProductColorRelation Id ProductId ColorId In ...

Converting a Promise to an Observable in Angular using Typescript

I have a working method that functions as intended: getdata(): Promise<any> { let query = `SELECT * FROM table`; return new Promise((resolve, reject) => { this.db.query(query, (error, rows) => { if(error) reject(error); ...

Enforce numerical input in input field by implementing a custom validator in Angular 2

After extensive research, I was unable to find a satisfactory solution to my query. Despite browsing through various Stack Overflow questions, none of them had an accepted answer. The desired functionality for the custom validator is to restrict input to ...

The issue of resolving NestJs ParseEnumPipe

I'm currently using the NestJs framework (which I absolutely adore) and I need to validate incoming data against an Enum in Typscript. Here's what I have: enum ProductAction { PURCHASE = 'PURCHASE', } @Patch('products/:uuid&apos ...

Tips for inserting a row component into a table using Angular 7

I am currently using the latest version of Angular (7.2.0). I have created a custom tr component as follows: import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'app-table-row', templateUrl: './table- ...