I have been using the Angular Material mat-menu for playlist selection. It’s Material Design’s version of a drop-down select, a classic original GUI prompt concept. There was a problem with long picklists on iPad, maybe due to the modification I did to make the picklist larger – for less scrolling. Also, I wanted a more modern and obvious UI. The user pretty much cannot do anything until picking a playlist. So let’s make picking the playlist a bigger deal up front.
I decided to get rid of the mat-menu and present each playlist as a clickable card. I knew this would be more work, and it was, but it was worth it.
Tabbing
Mat-menu supports the tab key. Once the drop-down appears, the tab key works to move through items. I want the same thing for my cards. So I added tabindex=0 to each card.
A tab key user likely will use the keyboard then to select – either the enter key or the space bar. With tabindex=0 the user can tab to a card, but then neither the enter key nor the space bar work for select. No key does. I solved this by binding to the keyup event, and making my function accept an optional parameter that gives me the keystroke. These lines of code are on each card:
style="margin:10px;cursor:pointer"
tabindex=0
(click)="onSelectPlaylist(PI)"
(keyup)="onSelectPlaylist(PI,$event.key)"
Then, in my function:
onSelectPlaylist(I: number, key?: string): void {
if (key && !key.match(/^( |Enter)$/)) {return}
...
Space bar really does send a single byte blank character through $event.key. The enter key, however, sends the string “Enter”. So my regular expression for space or enter is
/^( |Enter)$/
If the user triggers the function with any key other than space or enter, the function instantly returns, doing nothing.
Toggling
Just as with a classic drop-down select list, we want the cards to disappear when the user makes a selection, and of course reappear if the user wants to make a different selection. I spent a lot of time on this, trying many different user interface ideas. Here are a few things I learned along the way.
Avoid using *ngIf to toggle the existence of Angular Material’s paginator.
I advise this because if the user changes the items-per-page setting, it is lost when *ngIf removes the paginator from the DOM. This may not be a big deal at the time of removal, but be careful if the paginator might be subsequently restored.
Be sure hidden content is not tab selectable
I was using flex size zero to hide sections (eg. fxFlex=”0 1 0″ for the hidden state). I was horrified, however, when eventually I discovered that the user can still tab though, and trigger selection in, this hidden content. It’s much better to show/hide using [fxShow]. If you are unfamiliar with this syntax, it is from the nice flex-layout module that I am using.