Skip to content

Commit a190db0

Browse files
committed
fix(list): allow for list and list items to be disabled
Adds the ability to disable all variants of the list. Currently it's only the selection list that can be disabled. Fixes #17574.
1 parent 97a7e2b commit a190db0

File tree

4 files changed

+86
-16
lines changed

4 files changed

+86
-16
lines changed

src/material/list/list.scss

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,8 @@ mat-action-list {
278278
font: inherit;
279279
outline: inherit;
280280
-webkit-tap-highlight-color: transparent;
281-
282281
text-align: left;
282+
283283
[dir='rtl'] & {
284284
text-align: right;
285285
}
@@ -300,6 +300,10 @@ mat-action-list {
300300
outline: none;
301301
}
302302

303+
.mat-list-item-disabled {
304+
pointer-events: none;
305+
}
306+
303307
@include cdk-high-contrast {
304308
.mat-selection-list:focus {
305309
outline-style: dotted;

src/material/list/list.spec.ts

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ describe('MatList', () => {
1616
ListWithOneAnchorItem, ListWithOneItem, ListWithTwoLineItem, ListWithThreeLineItem,
1717
ListWithAvatar, ListWithItemWithCssClass, ListWithDynamicNumberOfLines,
1818
ListWithMultipleItems, ListWithManyLines, NavListWithOneAnchorItem, ActionListWithoutType,
19-
ActionListWithType, ListWithIndirectDescendantLines
19+
ActionListWithType, ListWithIndirectDescendantLines, ListWithDisabledItems,
2020
],
2121
});
2222

@@ -275,8 +275,40 @@ describe('MatList', () => {
275275
expect(listItems[0].nativeElement.className).toContain('mat-2-line');
276276
expect(listItems[1].nativeElement.className).toContain('mat-2-line');
277277
});
278-
});
279278

279+
it('should be able to disable a single list item', () => {
280+
const fixture = TestBed.createComponent(ListWithDisabledItems);
281+
const listItems: HTMLElement[] =
282+
Array.from(fixture.nativeElement.querySelectorAll('mat-list-item'));
283+
fixture.detectChanges();
284+
285+
expect(listItems.map(item => {
286+
return item.classList.contains('mat-list-item-disabled');
287+
})).toEqual([false, false, false]);
288+
289+
fixture.componentInstance.firstItemDisabled = true;
290+
fixture.detectChanges();
291+
292+
expect(listItems.map(item => {
293+
return item.classList.contains('mat-list-item-disabled');
294+
})).toEqual([true, false, false]);
295+
});
296+
297+
it('should be able to disable the entire list', () => {
298+
const fixture = TestBed.createComponent(ListWithDisabledItems);
299+
const listItems: HTMLElement[] =
300+
Array.from(fixture.nativeElement.querySelectorAll('mat-list-item'));
301+
fixture.detectChanges();
302+
303+
expect(listItems.every(item => item.classList.contains('mat-list-item-disabled'))).toBe(false);
304+
305+
fixture.componentInstance.listDisabled = true;
306+
fixture.detectChanges();
307+
308+
expect(listItems.every(item => item.classList.contains('mat-list-item-disabled'))).toBe(true);
309+
});
310+
311+
});
280312

281313
class BaseTestList {
282314
items: any[] = [
@@ -425,3 +457,15 @@ class ListWithMultipleItems extends BaseTestList { }
425457
})
426458
class ListWithIndirectDescendantLines extends BaseTestList {
427459
}
460+
461+
462+
@Component({template: `
463+
<mat-list [disabled]="listDisabled">
464+
<mat-list-item [disabled]="firstItemDisabled">One</mat-list-item>
465+
<mat-list-item>Two</mat-list-item>
466+
<mat-list-item>Three</mat-list-item>
467+
</mat-list>`})
468+
class ListWithDisabledItems {
469+
firstItemDisabled = false;
470+
listDisabled = false;
471+
}

src/material/list/list.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {BooleanInput} from '@angular/cdk/coercion';
9+
import {coerceBooleanProperty, BooleanInput} from '@angular/cdk/coercion';
1010
import {
1111
AfterContentInit,
1212
ChangeDetectionStrategy,
@@ -21,22 +21,26 @@ import {
2121
OnChanges,
2222
OnDestroy,
2323
ChangeDetectorRef,
24+
Input,
2425
} from '@angular/core';
2526
import {
27+
CanDisable,
28+
CanDisableCtor,
2629
CanDisableRipple,
2730
CanDisableRippleCtor,
2831
MatLine,
2932
setLines,
3033
mixinDisableRipple,
34+
mixinDisabled,
3135
} from '@angular/material/core';
3236
import {Subject} from 'rxjs';
3337
import {takeUntil} from 'rxjs/operators';
3438

3539
// Boilerplate for applying mixins to MatList.
3640
/** @docs-private */
3741
class MatListBase {}
38-
const _MatListMixinBase: CanDisableRippleCtor & typeof MatListBase =
39-
mixinDisableRipple(MatListBase);
42+
const _MatListMixinBase: CanDisableRippleCtor & CanDisableCtor & typeof MatListBase =
43+
mixinDisabled(mixinDisableRipple(MatListBase));
4044

4145
// Boilerplate for applying mixins to MatListItem.
4246
/** @docs-private */
@@ -53,12 +57,12 @@ const _MatListItemMixinBase: CanDisableRippleCtor & typeof MatListItemBase =
5357
},
5458
templateUrl: 'list.html',
5559
styleUrls: ['list.css'],
56-
inputs: ['disableRipple'],
60+
inputs: ['disableRipple', 'disabled'],
5761
encapsulation: ViewEncapsulation.None,
5862
changeDetection: ChangeDetectionStrategy.OnPush,
5963
})
60-
export class MatNavList extends _MatListMixinBase implements CanDisableRipple, OnChanges,
61-
OnDestroy {
64+
export class MatNavList extends _MatListMixinBase implements CanDisable, CanDisableRipple,
65+
OnChanges, OnDestroy {
6266
/** Emits when the state of the list changes. */
6367
_stateChanges = new Subject<void>();
6468

@@ -71,6 +75,7 @@ export class MatNavList extends _MatListMixinBase implements CanDisableRipple, O
7175
}
7276

7377
static ngAcceptInputType_disableRipple: BooleanInput;
78+
static ngAcceptInputType_disabled: BooleanInput;
7479
}
7580

7681
@Component({
@@ -81,11 +86,12 @@ export class MatNavList extends _MatListMixinBase implements CanDisableRipple, O
8186
'class': 'mat-list mat-list-base'
8287
},
8388
styleUrls: ['list.css'],
84-
inputs: ['disableRipple'],
89+
inputs: ['disableRipple', 'disabled'],
8590
encapsulation: ViewEncapsulation.None,
8691
changeDetection: ChangeDetectionStrategy.OnPush,
8792
})
88-
export class MatList extends _MatListMixinBase implements CanDisableRipple, OnChanges, OnDestroy {
93+
export class MatList extends _MatListMixinBase implements CanDisable, CanDisableRipple, OnChanges,
94+
OnDestroy {
8995
/** Emits when the state of the list changes. */
9096
_stateChanges = new Subject<void>();
9197

@@ -120,6 +126,7 @@ export class MatList extends _MatListMixinBase implements CanDisableRipple, OnCh
120126
}
121127

122128
static ngAcceptInputType_disableRipple: BooleanInput;
129+
static ngAcceptInputType_disabled: BooleanInput;
123130
}
124131

125132
/**
@@ -158,6 +165,7 @@ export class MatListSubheaderCssMatStyler {}
158165
exportAs: 'matListItem',
159166
host: {
160167
'class': 'mat-list-item',
168+
'[class.mat-list-item-disabled]': 'disabled',
161169
// @breaking-change 8.0.0 Remove `mat-list-item-avatar` in favor of `mat-list-item-with-avatar`.
162170
'[class.mat-list-item-avatar]': '_avatar || _icon',
163171
'[class.mat-list-item-with-avatar]': '_avatar || _icon',
@@ -202,6 +210,14 @@ export class MatListItem extends _MatListItemMixinBase implements AfterContentIn
202210
}
203211
}
204212

213+
/** Whether the option is disabled. */
214+
@Input()
215+
get disabled() { return this._disabled || !!(this._list && this._list.disabled); }
216+
set disabled(value: boolean) {
217+
this._disabled = coerceBooleanProperty(value);
218+
}
219+
private _disabled = false;
220+
205221
ngAfterContentInit() {
206222
setLines(this._lines, this._element);
207223
}
@@ -223,4 +239,5 @@ export class MatListItem extends _MatListItemMixinBase implements AfterContentIn
223239
}
224240

225241
static ngAcceptInputType_disableRipple: BooleanInput;
242+
static ngAcceptInputType_disabled: BooleanInput;
226243
}

tools/public_api_guard/material/list.d.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
export declare const MAT_SELECTION_LIST_VALUE_ACCESSOR: any;
22

3-
export declare class MatList extends _MatListMixinBase implements CanDisableRipple, OnChanges, OnDestroy {
3+
export declare class MatList extends _MatListMixinBase implements CanDisable, CanDisableRipple, OnChanges, OnDestroy {
44
_stateChanges: Subject<void>;
55
constructor(_elementRef: ElementRef<HTMLElement>);
66
_getListType(): 'list' | 'action-list' | null;
77
ngOnChanges(): void;
88
ngOnDestroy(): void;
99
static ngAcceptInputType_disableRipple: BooleanInput;
10-
static ɵcmp: i0.ɵɵComponentDefWithMeta<MatList, "mat-list, mat-action-list", ["matList"], { "disableRipple": "disableRipple"; }, {}, never>;
10+
static ngAcceptInputType_disabled: BooleanInput;
11+
static ɵcmp: i0.ɵɵComponentDefWithMeta<MatList, "mat-list, mat-action-list", ["matList"], { "disableRipple": "disableRipple"; "disabled": "disabled"; }, {}, never>;
1112
static ɵfac: i0.ɵɵFactoryDef<MatList>;
1213
}
1314

@@ -25,13 +26,16 @@ export declare class MatListItem extends _MatListItemMixinBase implements AfterC
2526
_avatar: MatListAvatarCssMatStyler;
2627
_icon: MatListIconCssMatStyler;
2728
_lines: QueryList<MatLine>;
29+
get disabled(): boolean;
30+
set disabled(value: boolean);
2831
constructor(_element: ElementRef<HTMLElement>, _changeDetectorRef: ChangeDetectorRef, navList?: MatNavList, list?: MatList);
2932
_getHostElement(): HTMLElement;
3033
_isRippleDisabled(): boolean;
3134
ngAfterContentInit(): void;
3235
ngOnDestroy(): void;
3336
static ngAcceptInputType_disableRipple: BooleanInput;
34-
static ɵcmp: i0.ɵɵComponentDefWithMeta<MatListItem, "mat-list-item, a[mat-list-item], button[mat-list-item]", ["matListItem"], { "disableRipple": "disableRipple"; }, {}, ["_avatar", "_icon", "_lines"]>;
37+
static ngAcceptInputType_disabled: BooleanInput;
38+
static ɵcmp: i0.ɵɵComponentDefWithMeta<MatListItem, "mat-list-item, a[mat-list-item], button[mat-list-item]", ["matListItem"], { "disableRipple": "disableRipple"; "disabled": "disabled"; }, {}, ["_avatar", "_icon", "_lines"]>;
3539
static ɵfac: i0.ɵɵFactoryDef<MatListItem>;
3640
}
3741

@@ -82,12 +86,13 @@ export declare class MatListSubheaderCssMatStyler {
8286
static ɵfac: i0.ɵɵFactoryDef<MatListSubheaderCssMatStyler>;
8387
}
8488

85-
export declare class MatNavList extends _MatListMixinBase implements CanDisableRipple, OnChanges, OnDestroy {
89+
export declare class MatNavList extends _MatListMixinBase implements CanDisable, CanDisableRipple, OnChanges, OnDestroy {
8690
_stateChanges: Subject<void>;
8791
ngOnChanges(): void;
8892
ngOnDestroy(): void;
8993
static ngAcceptInputType_disableRipple: BooleanInput;
90-
static ɵcmp: i0.ɵɵComponentDefWithMeta<MatNavList, "mat-nav-list", ["matNavList"], { "disableRipple": "disableRipple"; }, {}, never>;
94+
static ngAcceptInputType_disabled: BooleanInput;
95+
static ɵcmp: i0.ɵɵComponentDefWithMeta<MatNavList, "mat-nav-list", ["matNavList"], { "disableRipple": "disableRipple"; "disabled": "disabled"; }, {}, never>;
9196
static ɵfac: i0.ɵɵFactoryDef<MatNavList>;
9297
}
9398

0 commit comments

Comments
 (0)