Skip to content

Commit 5a9b7b7

Browse files
committed
fix(material/list): add disabled attribute for mat-list-item buttons
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
1 parent 8f29413 commit 5a9b7b7

File tree

2 files changed

+62
-5
lines changed

2 files changed

+62
-5
lines changed

src/material/list/list-base.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export abstract class MatListBase {
7777
host: {
7878
'[class.mdc-list-item--disabled]': 'disabled',
7979
'[attr.aria-disabled]': 'disabled',
80+
'[attr.disabled]': '(_isButtonElement && disabled) || null',
8081
},
8182
})
8283
/** @docs-private */
@@ -98,6 +99,9 @@ export abstract class MatListItemBase implements AfterViewInit, OnDestroy, Rippl
9899
/** Host element for the list item. */
99100
_hostElement: HTMLElement;
100101

102+
/** indicate whether the host element is a button or not */
103+
_isButtonElement: boolean;
104+
101105
/** Whether animations are disabled. */
102106
_noopAnimations: boolean;
103107

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

182187
if (_listBase && !_listBase._isNonInteractive) {
@@ -186,10 +191,7 @@ export abstract class MatListItemBase implements AfterViewInit, OnDestroy, Rippl
186191
// If no type attribute is specified for a host `<button>` element, set it to `button`. If a
187192
// type attribute is already specified, we do nothing. We do this for backwards compatibility.
188193
// TODO: Determine if we intend to continue doing this for the MDC-based list.
189-
if (
190-
this._hostElement.nodeName.toLowerCase() === 'button' &&
191-
!this._hostElement.hasAttribute('type')
192-
) {
194+
if (this._isButtonElement && !this._hostElement.hasAttribute('type')) {
193195
this._hostElement.setAttribute('type', 'button');
194196
}
195197
}

src/material/list/list.spec.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {fakeAsync, TestBed, waitForAsync} from '@angular/core/testing';
22
import {dispatchFakeEvent, dispatchMouseEvent} from '@angular/cdk/testing/private';
3-
import {Component, QueryList, ViewChildren} from '@angular/core';
3+
import {Component, QueryList, ViewChild, ViewChildren} from '@angular/core';
44
import {By} from '@angular/platform-browser';
55
import {MatListItem, MatListModule} from './index';
66

@@ -22,6 +22,8 @@ describe('MDC-based MatList', () => {
2222
NavListWithActivatedItem,
2323
ActionListWithoutType,
2424
ActionListWithType,
25+
ActionListWithDisabledList,
26+
ActionListWithDisabledItem,
2527
ListWithDisabledItems,
2628
StandaloneListItem,
2729
],
@@ -377,6 +379,34 @@ describe('MDC-based MatList', () => {
377379
fixture.detectChanges();
378380
}).not.toThrow();
379381
});
382+
383+
it('should be able to disable and enable the entire action list', () => {
384+
const fixture = TestBed.createComponent(ActionListWithDisabledList);
385+
const listItems: HTMLElement[] = Array.from(
386+
fixture.nativeElement.querySelectorAll('[mat-list-item]'),
387+
);
388+
fixture.detectChanges();
389+
390+
expect(listItems.every(listItem => listItem.hasAttribute('disabled'))).toBe(true);
391+
392+
fixture.componentInstance.disableList = false;
393+
fixture.detectChanges();
394+
395+
expect(listItems.every(listItem => !listItem.hasAttribute('disabled'))).toBe(true);
396+
});
397+
398+
it('should be able to disable and enable button item', () => {
399+
const fixture = TestBed.createComponent(ActionListWithDisabledItem);
400+
const buttonItem: HTMLButtonElement = fixture.nativeElement.querySelector('[mat-list-item]');
401+
fixture.detectChanges();
402+
403+
expect(buttonItem.hasAttribute('disabled')).toBe(true);
404+
405+
fixture.componentInstance.buttonItem.disabled = false;
406+
fixture.detectChanges();
407+
408+
expect(buttonItem.hasAttribute('disabled')).toBe(false);
409+
});
380410
});
381411

382412
class BaseTestList {
@@ -460,6 +490,31 @@ class ActionListWithType extends BaseTestList {
460490
@ViewChildren(MatListItem) listItems: QueryList<MatListItem>;
461491
}
462492

493+
@Component({
494+
template: `
495+
<mat-action-list [disabled]="disableList">
496+
<button mat-list-item *ngFor="let item of items">
497+
{{item.name}}
498+
</button>
499+
</mat-action-list>`,
500+
})
501+
class ActionListWithDisabledList extends BaseTestList {
502+
disableList = true;
503+
}
504+
505+
@Component({
506+
template: `
507+
<mat-action-list>
508+
<button mat-list-item [disabled]="disableItem">
509+
Paprika
510+
</button>
511+
</mat-action-list>`,
512+
})
513+
class ActionListWithDisabledItem extends BaseTestList {
514+
@ViewChild(MatListItem) buttonItem: MatListItem;
515+
disableItem = true;
516+
}
517+
463518
@Component({
464519
template: `
465520
<mat-list>

0 commit comments

Comments
 (0)