The disabled attribute in Angular 2+ does not seem to work for a div element when attempting to loop through ngFor

I am currently developing an appointment booking application that showcases time slots for appointments by utilizing the *ngFor loop.

html

<div *ngFor="let item of allTimeSlots">
    <div class="col-sm-3">
        <div class="choice" data-toggle="wizard-slot" [attr.disabled]="item.status" (click)="slotSelected($event)">
            <input type="radio" name="slot" value="{{item.timeSlot}}">
            <span class="icon">{{item.timeSlot}}</span> {{item.status}}
        </div>
    </div>
</div>

typescript

for (var index = 0; index < this.totalMinutes; index += 15, i++) {
  this.allTimeSlots[i] = new allTimeSlots("", false);

  this.allTimeSlots[i].timeSlot = (hour <= 12 ? hour : hour - 12) + ":" + (minute <= 9 ? ("0" + minute) : minute) + " " + ampm;
  this.bookedTimeSlots.forEach(element => {
    if (this.allTimeSlots[i].timeSlot == element) {
      this.allTimeSlots[i].status = true;
    }
  });
}

Attached is a screenshot illustrating time slots, where 'true' indicates a booked slot and 'false' indicates availability for debugging purposes. https://i.sstatic.net/iGjrd.png

Although my code runs without errors, all div elements generated by *ngFor appear disabled. I attempted using *ngIf instead of disabled, which resolved the issue. However, I aim to show the availability status of time slots.

Answer №1

Here is the recommended usage:

[attr.disabled]="isDisabled ? '' : null"

This also applies to readonly.

Answer №2

When you want to disable an element, use [disabled] instead of [attr.disabled]

This is important because using [attr.disabled]="false" will still result in the element being disabled since it adds disabled="false" to the element.

Examples of Syntax that Will Not Disable an Element

<button>Not Disabled</button>
<button [disabled]="false">Not Disabled</button>

Examples of Syntax that Will Disable an Element

<button disabled></button>
<button disabled="true"></button>
<button disabled="false"></button>
<button [attr.disabled]="true"></button>
<button [attr.disabled]="false"></button>
<button [disabled]="true"></button>

The presence of the disabled attribute will always disable an element, regardless of whether its value is true or false. Angular won't include the disabled attribute at all if you use [disabled]="variable" and variable is set to false.

If you are not using buttons but div elements which Angular 2 doesn't recognize the disabled attribute for, you can work around this by using [ngClass] like so:

<div [ngClass]="{ 'disabled': item.status }"></div>

You can then style the element based on its status in CSS to indicate if a time slot is booked or not.

For more details on [ngClass], refer to the official documentation

Answer №3

To clarify, the "disabled" attribute cannot be used for a div element. It is only valid for the following elements:

<button>    
<fieldset>  
<input> 
<keygen>    
<optgroup>  
<option>    
<select>    
<textarea>  

More information can be found here

If you need to address this issue, you can implement the following solution:

<div 
  class="choice" 
  data-toggle="wizard-slot" 
  [class.disabled]="item.status" 
  (click)="slotSelected($event)">
  <input 
    type="radio" 
    name="slot" 
    value="{{item.timeSlot}}" 
    [disabled]="item.status">
  <span class="icon">{{item.timeSlot}}</span> {{item.status}}
</div>

Additionally, don't forget to add the necessary styles:

.disabled {
  cursor: not-allowed;
}

Answer №4

CSS

.inactive-element {
  pointer-events: none;
  opacity: 0.4;
}

HTML

<div [class.inactive-element]="!isElementActive"></div>

TS

isElementActive: boolean;

You have the ability to change the status of isElementActive at any point.

Answer №5

As advised by 0mpurdy, it is recommended to utilize the [disabled] attribute. The variable itself does not necessarily need to be a boolean, but the expression should be.

In your particular scenario, it checks whether item.status evaluates to false or true. Therefore, if it's not null/NaN/undefined, the result will be "true" and consequently the div will be disabled.

Consider incorporating this expression instead:

[disabled]="item.status === 'occupied'"


Update

I apologize for overlooking that detail. Given that you cannot disable a div, insert the disabled attribute within the input tag.

<input type="radio" [disabled]="item.status === 'occupied'" name="slot" value="{{item.timeSlot}}">

Since you desire to exhibit the selection as disabled, it's necessary to place it directly inside the input. This way, the radio button will be unclickable and a 'cursor: not-allowed' will be displayed.

I trust this information proves helpful.

Answer №6

Using an attribute directive can be very helpful when it comes to disabling or enabling a div or any other HTML element along with its child elements.

DisableDirective

To start, create an attribute directive that accepts a parameter (appDisable) as input. This directive will allow you to disable or enable DOM elements and their respective child elements based on the provided input.

import { AfterViewInit, Directive, ElementRef, Input, OnChanges, Renderer2 } from '@angular/core';

const DISABLED = 'disabled';
const APP_DISABLED = 'app-disabled';
const TAB_INDEX = 'tabindex';
const TAG_ANCHOR = 'a';

@Directive({
  selector: '[appDisable]'
})
export class DisableDirective implements OnChanges, AfterViewInit {

  @Input() appDisable = true;

  constructor(private eleRef: ElementRef, private renderer: Renderer2) { }

  ngOnChanges() {
    this.disableElement(this.eleRef.nativeElement);
  }

  ngAfterViewInit() {
    this.disableElement(this.eleRef.nativeElement);
  }

  private disableElement(element: any) {
    if (this.appDisable) {
      if (!element.hasAttribute(DISABLED)) {
        this.renderer.setAttribute(element, APP_DISABLED, '');
        this.renderer.setAttribute(element, DISABLED, 'true');

        // disabling anchor tag keyboard event
        if (element.tagName.toLowerCase() === TAG_ANCHOR) {
          this.renderer.setAttribute(element, TAB_INDEX, '-1');
        }
      }
    } else {
      if (element.hasAttribute(APP_DISABLED)) {
        if (element.getAttribute('disabled') !== '') {
          element.removeAttribute(DISABLED);
        }
        element.removeAttribute(APP_DISABLED);
        if (element.tagName.toLowerCase() === TAG_ANCHOR) {
          element.removeAttribute(TAB_INDEX);
        }
      }
    }
    if (element.children) {
      for (let ele of element.children) {
        this.disableElement(ele);
      }
    }
  }
}

Remember to register the DisableDirective in the AppModule

How to implement the directive in your component?
Simply pass a boolean value (true/false) in the directive from the component.

<div class="container" [appDisable]="true">
</div>

You can find more information in the complete post HERE

See a live example on Stackblitz

Answer №7

If you're looking to achieve this, consider utilizing attribute binding. It's a straightforward approach. Take a look at the documentation for guidance on implementation.

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

Difficulties arise when attempting to install nodejs on linux using the npm install nodejs command

While attempting to execute... npm install nodejs I encounter the subsequent issue: npm WARN optional Skipping failed optional dependency /chokidar/fsevents: npm WARN notsup Not compatible with your operating system or architecture: [email prot ...

Having trouble typing a RequestHandler in Express JS using TypeScript?

I am trying to create a RequestHandler that types the req.params and req.body with these interfaces interface UpdateNoteParams { noteId: string, } interface UpdateNoteBody { title?: string, text?: string, } This is what I have tried so far: e ...

The useEffect hook in React is signaling a missing dependency issue

Any tips on how to resolve warnings such as this one src\components\pages\badge\BadgeScreen.tsx Line 87:6: React Hook useEffect has a missing dependency: 'loadData'. Either include it or remove the dependency array react-hoo ...

Original: Generic for type guard functionRewritten: Universal

I have successfully created a function that filters a list of two types into two separate lists of unique type using hardcoded types: interface TypeA { kind: 'typeA'; } interface TypeB { kind: 'typeB'; } filterMixedList(mixedList$: ...

Sharing cookies between the browser and server in Angular Universal

After trying to integrate cookies in browser and server using the example from this link, I encountered an issue. The cookies do not appear to be shared between the browser and the server. The cookie I set on the browser side is visible, but when I try to ...

I recently updated Angular Cli and now my app is searching for node_modules in a different location. Is there a way for me to revert it

Current Versions. @angular/cli: 1.4.2 node: 6.10.0 os: linux x64 @angular/animations: 4.3.6 @angular/common: 4.3.6 @angular/compiler: 4.3.6 @angular/compiler-cli: 4.3.6 @angular/core: 4.3.6 @angular/forms: 4.3.6 @angular/http: 4.3.6 @angular/platform-brow ...

Why should we include the '#' character in jhipster URLs?

Standard Angular applications typically do not include a '#' sign in their URLs. However, in JHipster URLs, the '#' character serves a specific purpose. Can you explain the significance of the '#' symbol in JHipster URLs and h ...

Resolve routing problems with lazy loading in Angular7

I have been working on implementing lazy loading in my Angular project. However, I am encountering the same error even after following the suggested solution. Lazy loading error on StackOverflow I have exported the components from the project module and im ...

Tips for utilizing regex to locate words and spaces within a text?

I'm feeling so frustrated and lost right now. Any help you can offer would be greatly appreciated. I am currently dealing with an issue in Katex and Guppy keyboard. My goal is to create a regex that will identify the word matrix, locate the slash that ...

Unleashed Breakpoint Mystery in Ionic 5 Angular with VSCode

I recently upgraded my Ionic 5 Angular 12 app from Ionic 4 Angular 8. The application is working well and remains stable, but I have encountered some issues while debugging. Firstly, when I use the launch.json file in Visual Studio Code to run the app, it ...

Creating a JSON file from a custom key-value class in Typescript: A comprehensive guide

I am struggling to find an npm package or create my own function that can generate a JSON file from elements within this specific class: export class TranslatedFileElement { private key: string private hasChild: boolean priva ...

A unique column in the Foundry system that utilizes function-backed technology to calculate the monthly usage of engines over a

In my dataset of ‘Engine Hours’, I have the following information: Engine# Date Recorded Hours ABC123 Jan 21, 2024 9,171 ABC123 Dec 13, 2023 9,009 ABC123 Oct 6, 2023 8,936 XYZ456 Jan 8, 2024 5,543 XYZ456 Nov 1, 2023 4,998 XYZ456 Oct 1 ...

Refreshing the view in Angular2 after rejecting changes in a text input field

I have multiple text areas in an array, each of which can be edited individually and the changes can either be saved or discarded. Every textarea has an associated object to monitor the modifications and enable/disable specific buttons. While everything se ...

What is preventing me from assigning to a class variable within a $http success handler?

During the course of my project, I have encountered a perplexing situation that is difficult to comprehend. My intuition tells me that the issue lies in a peculiar nuance of javascript while I am working in TypeScript. Unfortunately, I am unable to prove t ...

When running ng serve, I encountered the following error message: "ERROR in Error: Internal Error: The name element has already been defined within the scope as [object Object]."

Details of Angular CLI and Node environment: - Angular CLI: 10.0.4 - Node: 12.13.0 - OS: linux x64 - Angular: 10.0.7 - Ivy Workspace: Yes List of Packages and Versions: - @angular-devkit/architect: 0.1000.4 - @angular-devkit/build-angular: 0 ...

Error encountered while working with SVG in a functional React component with typescript

I have a customized icon component that looks like this: import React from 'react'; type IconProps = { width?: number; height?: number; color?: string; styleName?:string; }; const MyIcon: React.FC<IconProps> = ({ width ...

The specified property 'length' is not found on type OkPacket within the mysql2 module

In my code example below, I am simply showcasing a specific scenario: this.getCode = (code: string): Promise<codeObject | false> => { return new Promise((resolve, reject) => { pool.query('SELECT * FROM ?? WHERE code = ...

Displaying a div component in React and Typescript upon clicking an element

I've been working on a to-do list project using React and TypeScript. In order to display my completed tasks, I have added a "done" button to the DOM that triggers a function when clicked. Initially, I attempted to use a useState hook in the function ...

Deactivate the SCSS styling for the last of its type

I have created a page using typescript which includes .html, .ts and .scss files. When I run my website and inspect the page in Google, I noticed that the table has code inside td.mat-cell:last-of-type with padding-right: 24px There is no mention of this ...

Methods for defining a variable in React with Typescript without encountering the "Index signature is missing in type" issue

I am facing an issue while trying to declare a variable 'reports' and assigning it to an array of arrays containing string and number types. The problem arises when I try to assign it, resulting in errors. ... // Retrieving data from an API let ...