Skip to content

Commit

Permalink
110088: changes to keyboard navigation / selection
Browse files Browse the repository at this point in the history
  • Loading branch information
Jens Vannerum committed Jan 22, 2024
1 parent 3a265bb commit 05eb212
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
(keydown)="selectOnKeyDown($event, sdRef)">
</div>

<div ngbDropdownMenu
<div #dropdownMenu ngbDropdownMenu
class="dropdown-menu scrollable-dropdown-menu w-100"
aria-haspopup="true"
aria-expanded="false"
Expand All @@ -42,7 +42,8 @@
[scrollWindow]="false">

<button class="dropdown-item disabled" *ngIf="optionsList && optionsList.length == 0">{{'form.no-results' | translate}}</button>
<button class="dropdown-item collection-item text-truncate" *ngFor="let listEntry of optionsList"
<button class="dropdown-item collection-item text-truncate" *ngFor="let listEntry of optionsList; let i = index"
[class.active]="i === selectedIndex"
(keydown.enter)="onSelect(listEntry); sdRef.close()" (mousedown)="onSelect(listEntry); sdRef.close()"
title="{{ listEntry.display }}" role="option"
[attr.id]="listEntry.display == (currentValue|async) ? ('combobox_' + id + '_selected') : null">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import {
ChangeDetectorRef,
Component,
EventEmitter,
Input,
OnInit,
Output,
ViewChild,
ElementRef
} from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';

import { Observable, of as observableOf } from 'rxjs';
Expand Down Expand Up @@ -28,6 +37,8 @@ import { FormFieldMetadataValueObject } from '../../../models/form-field-metadat
templateUrl: './dynamic-scrollable-dropdown.component.html'
})
export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyComponent implements OnInit {
@ViewChild('dropdownMenu', { read: ElementRef }) dropdownMenu: ElementRef;

@Input() bindId = true;
@Input() group: UntypedFormGroup;
@Input() model: DynamicScrollableDropdownModel;
Expand All @@ -41,6 +52,7 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
public pageInfo: PageInfo;
public optionsList: any;
public inputText: string = null;
public selectedIndex = 0;
public acceptableKeys = ['Space', 'NumpadMultiply', 'NumpadAdd', 'NumpadSubtract', 'NumpadDecimal', 'Semicolon', 'Equal', 'Comma', 'Minus', 'Period', 'Quote', 'Backquote'];

constructor(protected vocabularyService: VocabularyService,
Expand Down Expand Up @@ -73,6 +85,7 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
list.pageInfo.totalElements,
list.pageInfo.totalPages
);
this.selectedIndex = 0;
this.cdr.detectChanges();
});
}
Expand All @@ -96,6 +109,23 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
}
}

navigateDropdown(event: KeyboardEvent) {
if (event.key === 'ArrowDown') {
this.selectedIndex = Math.min(this.selectedIndex + 1, this.optionsList.length - 1);
} else if (event.key === 'ArrowUp') {
this.selectedIndex = Math.max(this.selectedIndex - 1, 0);
}
this.scrollToSelected();
}

scrollToSelected() {
const dropdownItems = this.dropdownMenu.nativeElement.querySelectorAll('.dropdown-item');
const selectedItem = dropdownItems[this.selectedIndex];
if (selectedItem) {
selectedItem.scrollIntoView({ block: 'nearest' });
}
}

/**
* KeyDown handler to allow toggling the dropdown via keyboard
* @param event KeyboardEvent
Expand All @@ -104,12 +134,19 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
selectOnKeyDown(event: KeyboardEvent, sdRef: NgbDropdown) {
const keyName = event.key;

if (keyName === ' ' || keyName === 'Enter') {
if (keyName === 'Enter') {
event.preventDefault();
event.stopPropagation();
sdRef.toggle();
if (sdRef.isOpen()) {
this.onSelect(this.optionsList[this.selectedIndex]);
sdRef.close();
} else {
sdRef.open();
}
} else if (keyName === 'ArrowDown' || keyName === 'ArrowUp') {
this.openDropdown(sdRef);
event.preventDefault();
event.stopPropagation();
this.navigateDropdown(event);
} else if (keyName === 'Backspace') {
this.removeKeyFromInput();
} else if (this.isAcceptableKey(keyName)) {
Expand Down

0 comments on commit 05eb212

Please sign in to comment.