Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(selection-list): do not allow toggling disabled options #12617

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/lib/list/selection-list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,21 @@ describe('MatSelectionList without forms', () => {
expect(ENTER_EVENT.defaultPrevented).toBe(true);
});

it('should not be able to toggle a disabled option using SPACE', () => {
const testListItem = listOptions[1].nativeElement as HTMLElement;
const selectionModel = selectionList.componentInstance.selectedOptions;

expect(selectionModel.selected.length).toBe(0);

listOptions[1].componentInstance.disabled = true;

dispatchFakeEvent(testListItem, 'focus');
selectionList.componentInstance._keydown(createKeyboardEvent('keydown', SPACE, testListItem));
fixture.detectChanges();

expect(selectionModel.selected.length).toBe(0);
});

it('should restore focus if active option is destroyed', () => {
const manager = selectionList.componentInstance._keyManager;

Expand Down
17 changes: 7 additions & 10 deletions src/lib/list/selection-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,12 +410,9 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
switch (keyCode) {
case SPACE:
case ENTER:
if (!this.disabled) {
this._toggleSelectOnFocusedOption();

// Always prevent space from scrolling the page since the list has focus
event.preventDefault();
}
this._toggleFocusedOptionIfEnabled();
// Always prevent space from scrolling the page since the list has focus
event.preventDefault();
break;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be simpler to fix the issue by having a return here instead of the break?

Copy link
Member Author

@devversion devversion Aug 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does the issue relate to the break here? The issue is that we just check the state of SelectionList#disabled instead of looking at the disabled state of the individual option that should be toggled.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, sorry I misread it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, I've updated the PR description to explain what's causing the issue.

case HOME:
case END:
Expand All @@ -434,7 +431,7 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu

if ((keyCode === UP_ARROW || keyCode === DOWN_ARROW) && event.shiftKey &&
manager.activeItemIndex !== previousFocusIndex) {
this._toggleSelectOnFocusedOption();
this._toggleFocusedOptionIfEnabled();
}
}

Expand Down Expand Up @@ -492,14 +489,14 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
return this.options.filter(option => option.selected).map(option => option.value);
}

/** Toggles the selected state of the currently focused option. */
private _toggleSelectOnFocusedOption(): void {
/** Toggles the state of the currently focused option if enabled. */
private _toggleFocusedOptionIfEnabled(): void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though this method is private, the naming sounds weird. If we end up doing this, instead of what I mentioned above, I think it should be turned into _getFocusedOption and then the place it gets consumed would check whether it's disabled.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on Slack. In my opinion, this would result in code duplication that can be avoided by just having such a method.

I'm not sure about the method name, though. I agree that IfEnabled sounds weird. For now, changed it to just _toggleFocusedOption.

let focusedIndex = this._keyManager.activeItemIndex;

if (focusedIndex != null && this._isValidIndex(focusedIndex)) {
let focusedOption: MatListOption = this.options.toArray()[focusedIndex];

if (focusedOption) {
if (focusedOption && !focusedOption.disabled) {
focusedOption.toggle();

// Emit a change event because the focused option changed its state through user
Expand Down