@@ -145,8 +146,16 @@ Dogs
Selected: {{selectedOptions | json}}
Change Event Count {{changeEventCount}}
Model Change Event Count {{modelChangeEventCount}}
- Disable Selection List
-
+
+
+ Disable Selection List
+
+
+
+
+ Disable Selection List ripples
+
+
diff --git a/src/dev-app/list/list-demo.ts b/src/dev-app/list/list-demo.ts
index be6444af5d3e..bdee71397b2e 100644
--- a/src/dev-app/list/list-demo.ts
+++ b/src/dev-app/list/list-demo.ts
@@ -60,6 +60,7 @@ export class ListDemo {
thirdLine = false;
infoClicked = false;
selectionListDisabled = false;
+ selectionListRippleDisabled = false;
selectedOptions: string[] = ['apples'];
changeEventCount = 0;
diff --git a/src/lib/list/selection-list.spec.ts b/src/lib/list/selection-list.spec.ts
index f058837d9bd7..a1acfbe4ee3e 100644
--- a/src/lib/list/selection-list.spec.ts
+++ b/src/lib/list/selection-list.spec.ts
@@ -4,6 +4,7 @@ import {
dispatchFakeEvent,
dispatchEvent,
dispatchKeyboardEvent,
+ dispatchMouseEvent,
} from '@angular/cdk/testing';
import {
Component,
@@ -13,7 +14,7 @@ import {
ViewChildren,
} from '@angular/core';
import {async, ComponentFixture, fakeAsync, TestBed, tick, flush} from '@angular/core/testing';
-import {MatRipple} from '@angular/material/core';
+import {MatRipple, defaultRippleAnimationConfig} from '@angular/material/core';
import {By} from '@angular/platform-browser';
import {
MatListModule,
@@ -521,6 +522,33 @@ describe('MatSelectionList without forms', () => {
expect(list.options.toArray().every(option => option.selected)).toBe(true);
});
+ it('should disable list item ripples when the ripples on the list have been disabled',
+ fakeAsync(() => {
+ const rippleTarget = fixture.nativeElement
+ .querySelector('.mat-list-option:not(.mat-list-item-disabled) .mat-list-item-content');
+ const {enterDuration, exitDuration} = defaultRippleAnimationConfig;
+
+ dispatchMouseEvent(rippleTarget, 'mousedown');
+ dispatchMouseEvent(rippleTarget, 'mouseup');
+
+ expect(rippleTarget.querySelectorAll('.mat-ripple-element').length)
+ .toBe(1, 'Expected ripples to be enabled by default.');
+
+ // Wait for the ripples to go away.
+ tick(enterDuration + exitDuration);
+ expect(rippleTarget.querySelectorAll('.mat-ripple-element').length)
+ .toBe(0, 'Expected ripples to go away.');
+
+ fixture.componentInstance.listRippleDisabled = true;
+ fixture.detectChanges();
+
+ dispatchMouseEvent(rippleTarget, 'mousedown');
+ dispatchMouseEvent(rippleTarget, 'mouseup');
+
+ expect(rippleTarget.querySelectorAll('.mat-ripple-element').length)
+ .toBe(0, 'Expected no ripples after list ripples are disabled.');
+ }));
+
});
describe('with list option selected', () => {
@@ -1091,7 +1119,10 @@ describe('MatSelectionList with forms', () => {
@Component({template: `
-
+
Inbox (disabled selection-option)
@@ -1108,6 +1139,7 @@ describe('MatSelectionList with forms', () => {
`})
class SelectionListWithListOptions {
showLastOption: boolean = true;
+ listRippleDisabled = false;
onValueChange(_change: MatSelectionListChange) {}
}
diff --git a/src/lib/list/selection-list.ts b/src/lib/list/selection-list.ts
index 3022bba7cc0f..cb7d00bd6c3b 100644
--- a/src/lib/list/selection-list.ts
+++ b/src/lib/list/selection-list.ts
@@ -38,6 +38,8 @@ import {
QueryList,
ViewChild,
ViewEncapsulation,
+ SimpleChanges,
+ OnChanges,
} from '@angular/core';
import {
CanDisableRipple, CanDisableRippleCtor,
@@ -299,7 +301,7 @@ export class MatListOption extends _MatListOptionMixinBase
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MatSelectionList extends _MatSelectionListMixinBase implements FocusableOption,
- CanDisableRipple, AfterContentInit, ControlValueAccessor, OnDestroy {
+ CanDisableRipple, AfterContentInit, ControlValueAccessor, OnDestroy, OnChanges {
/** The FocusKeyManager which handles focus. */
_keyManager: FocusKeyManager;
@@ -331,9 +333,7 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
// strategy. Therefore the options will not check for any changes if the `MatSelectionList`
// changed its state. Since we know that a change to `disabled` property of the list affects
// the state of the options, we manually mark each option for check.
- if (this.options) {
- this.options.forEach(option => option._markForCheck());
- }
+ this._markOptionsForCheck();
}
private _disabled: boolean = false;
@@ -387,6 +387,14 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
});
}
+ ngOnChanges(changes: SimpleChanges) {
+ const disableRippleChanges = changes.disableRipple;
+
+ if (disableRippleChanges && !disableRippleChanges.firstChange) {
+ this._markOptionsForCheck();
+ }
+ }
+
ngOnDestroy() {
this._modelChanges.unsubscribe();
}
@@ -581,4 +589,11 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
private _getOptionIndex(option: MatListOption): number {
return this.options.toArray().indexOf(option);
}
+
+ /** Marks all the options to be checked in the next change detection run. */
+ private _markOptionsForCheck() {
+ if (this.options) {
+ this.options.forEach(option => option._markForCheck());
+ }
+ }
}
diff --git a/tools/public_api_guard/lib/list.d.ts b/tools/public_api_guard/lib/list.d.ts
index 9a399e3c7a84..97b751a59110 100644
--- a/tools/public_api_guard/lib/list.d.ts
+++ b/tools/public_api_guard/lib/list.d.ts
@@ -81,7 +81,7 @@ export declare class MatNavList extends _MatListMixinBase implements CanDisableR
ngOnDestroy(): void;
}
-export declare class MatSelectionList extends _MatSelectionListMixinBase implements FocusableOption, CanDisableRipple, AfterContentInit, ControlValueAccessor, OnDestroy {
+export declare class MatSelectionList extends _MatSelectionListMixinBase implements FocusableOption, CanDisableRipple, AfterContentInit, ControlValueAccessor, OnDestroy, OnChanges {
_keyManager: FocusKeyManager;
_onTouched: () => void;
compareWith: (o1: any, o2: any) => boolean;
@@ -99,6 +99,7 @@ export declare class MatSelectionList extends _MatSelectionListMixinBase impleme
deselectAll(): void;
focus(): void;
ngAfterContentInit(): void;
+ ngOnChanges(changes: SimpleChanges): void;
ngOnDestroy(): void;
registerOnChange(fn: (value: any) => void): void;
registerOnTouched(fn: () => void): void;