Skip to content

Commit

Permalink
fix(material/list): add disabled attribute for mat-list-item buttons (#…
Browse files Browse the repository at this point in the history
…26672)

Previously, mat-list-item buttons did not have the disabled attribute set when either the mat-list-item or the mat-action-list are disabled.
This commit adds the disabled attribute to mat-list-item buttons when it should be applied.
Fixes #26574

 BREAKING CHANGE: NO

(cherry picked from commit b06008b)
  • Loading branch information
hamzajazyri authored and mmalerba committed Feb 28, 2023
1 parent b71fa77 commit a87735e
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 5 deletions.
10 changes: 6 additions & 4 deletions src/material/list/list-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export abstract class MatListBase {
host: {
'[class.mdc-list-item--disabled]': 'disabled',
'[attr.aria-disabled]': 'disabled',
'[attr.disabled]': '(_isButtonElement && disabled) || null',
},
})
/** @docs-private */
Expand All @@ -98,6 +99,9 @@ export abstract class MatListItemBase implements AfterViewInit, OnDestroy, Rippl
/** Host element for the list item. */
_hostElement: HTMLElement;

/** indicate whether the host element is a button or not */
_isButtonElement: boolean;

/** Whether animations are disabled. */
_noopAnimations: boolean;

Expand Down Expand Up @@ -177,6 +181,7 @@ export abstract class MatListItemBase implements AfterViewInit, OnDestroy, Rippl
) {
this.rippleConfig = globalRippleOptions || {};
this._hostElement = this._elementRef.nativeElement;
this._isButtonElement = this._hostElement.nodeName.toLowerCase() === 'button';
this._noopAnimations = animationMode === 'NoopAnimations';

if (_listBase && !_listBase._isNonInteractive) {
Expand All @@ -186,10 +191,7 @@ export abstract class MatListItemBase implements AfterViewInit, OnDestroy, Rippl
// If no type attribute is specified for a host `<button>` element, set it to `button`. If a
// type attribute is already specified, we do nothing. We do this for backwards compatibility.
// TODO: Determine if we intend to continue doing this for the MDC-based list.
if (
this._hostElement.nodeName.toLowerCase() === 'button' &&
!this._hostElement.hasAttribute('type')
) {
if (this._isButtonElement && !this._hostElement.hasAttribute('type')) {
this._hostElement.setAttribute('type', 'button');
}
}
Expand Down
57 changes: 56 additions & 1 deletion src/material/list/list.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {fakeAsync, TestBed, waitForAsync} from '@angular/core/testing';
import {dispatchFakeEvent, dispatchMouseEvent} from '@angular/cdk/testing/private';
import {Component, QueryList, ViewChildren} from '@angular/core';
import {Component, QueryList, ViewChild, ViewChildren} from '@angular/core';
import {By} from '@angular/platform-browser';
import {MatListItem, MatListModule} from './index';

Expand All @@ -22,6 +22,8 @@ describe('MDC-based MatList', () => {
NavListWithActivatedItem,
ActionListWithoutType,
ActionListWithType,
ActionListWithDisabledList,
ActionListWithDisabledItem,
ListWithDisabledItems,
StandaloneListItem,
],
Expand Down Expand Up @@ -377,6 +379,34 @@ describe('MDC-based MatList', () => {
fixture.detectChanges();
}).not.toThrow();
});

it('should be able to disable and enable the entire action list', () => {
const fixture = TestBed.createComponent(ActionListWithDisabledList);
const listItems: HTMLElement[] = Array.from(
fixture.nativeElement.querySelectorAll('[mat-list-item]'),
);
fixture.detectChanges();

expect(listItems.every(listItem => listItem.hasAttribute('disabled'))).toBe(true);

fixture.componentInstance.disableList = false;
fixture.detectChanges();

expect(listItems.every(listItem => !listItem.hasAttribute('disabled'))).toBe(true);
});

it('should be able to disable and enable button item', () => {
const fixture = TestBed.createComponent(ActionListWithDisabledItem);
const buttonItem: HTMLButtonElement = fixture.nativeElement.querySelector('[mat-list-item]');
fixture.detectChanges();

expect(buttonItem.hasAttribute('disabled')).toBe(true);

fixture.componentInstance.buttonItem.disabled = false;
fixture.detectChanges();

expect(buttonItem.hasAttribute('disabled')).toBe(false);
});
});

class BaseTestList {
Expand Down Expand Up @@ -460,6 +490,31 @@ class ActionListWithType extends BaseTestList {
@ViewChildren(MatListItem) listItems: QueryList<MatListItem>;
}

@Component({
template: `
<mat-action-list [disabled]="disableList">
<button mat-list-item *ngFor="let item of items">
{{item.name}}
</button>
</mat-action-list>`,
})
class ActionListWithDisabledList extends BaseTestList {
disableList = true;
}

@Component({
template: `
<mat-action-list>
<button mat-list-item [disabled]="disableItem">
Paprika
</button>
</mat-action-list>`,
})
class ActionListWithDisabledItem extends BaseTestList {
@ViewChild(MatListItem) buttonItem: MatListItem;
disableItem = true;
}

@Component({
template: `
<mat-list>
Expand Down

0 comments on commit a87735e

Please sign in to comment.