{"id":311,"date":"2018-07-12T19:51:49","date_gmt":"2018-07-12T19:51:49","guid":{"rendered":"http:\/\/www.bullcrane.com\/angular\/?p=311"},"modified":"2018-07-18T03:46:30","modified_gmt":"2018-07-18T03:46:30","slug":"a-more-inviting-playlist-picker","status":"publish","type":"post","link":"http:\/\/www.bullcrane.com\/angular\/2018\/07\/12\/a-more-inviting-playlist-picker\/","title":{"rendered":"A more inviting playlist picker"},"content":{"rendered":"<p>I have been using the Angular Material <a href=\"https:\/\/material.angular.io\/components\/menu\/overview\">mat-menu<\/a> for playlist selection.  It&#8217;s Material Design&#8217;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 &#8211; 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&#8217;s make picking the playlist a bigger deal up front.<\/p>\n<p>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.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.bullcrane.com\/angular\/wp-content\/uploads\/2018\/07\/playlist_cards.png\" alt=\"\" width=\"580\" height=\"280\" class=\"alignnone size-full wp-image-312\" srcset=\"http:\/\/www.bullcrane.com\/angular\/wp-content\/uploads\/2018\/07\/playlist_cards.png 580w, http:\/\/www.bullcrane.com\/angular\/wp-content\/uploads\/2018\/07\/playlist_cards-300x145.png 300w\" sizes=\"(max-width: 580px) 100vw, 580px\" \/><\/p>\n<h6>Tabbing<\/h6>\n<p>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.<\/p>\n<p>A tab key user likely will use the keyboard then to select &#8211; 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:<\/p>\n<pre>style=\"margin:10px;cursor:pointer\"\r\ntabindex=0\r\n(click)=\"onSelectPlaylist(PI)\"\r\n(keyup)=\"onSelectPlaylist(PI,$event.key)\"<\/pre>\n<p>Then, in my function:<\/p>\n<pre>onSelectPlaylist(I: number, key?: string): void {\r\n  if (key && !key.match(\/^( |Enter)$\/)) {return}\r\n  ...<\/pre>\n<p>Space bar really does send a single byte blank character through $event.key.  The enter key, however, sends the string &#8220;Enter&#8221;.  So my regular expression for <em>space or enter<\/em> is <\/p>\n<pre>\/^( |Enter)$\/<\/pre>\n<p>If the user triggers the function with any key other than space or enter, the function instantly returns, doing nothing.<\/p>\n<h6>Toggling<\/h6>\n<p>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.<\/p>\n<p><strong>Avoid using *ngIf to toggle the existence of Angular Material&#8217;s paginator.<\/strong><\/p>\n<p><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.bullcrane.com\/angular\/wp-content\/uploads\/2018\/07\/material_paginator.png\" alt=\"\" width=\"475\" height=\"79\" class=\"alignnone size-full wp-image-317\" srcset=\"http:\/\/www.bullcrane.com\/angular\/wp-content\/uploads\/2018\/07\/material_paginator.png 475w, http:\/\/www.bullcrane.com\/angular\/wp-content\/uploads\/2018\/07\/material_paginator-300x50.png 300w\" sizes=\"(max-width: 475px) 100vw, 475px\" \/><\/p>\n<p>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.<\/p>\n<p><strong>Be sure hidden content is not tab selectable<\/strong><\/p>\n<p>I was using flex size zero to hide sections (eg. fxFlex=&#8221;0 1 0&#8243; 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&#8217;s much better to show\/hide using [fxShow].  If you are unfamiliar with this syntax, it is from the nice <a href=\"https:\/\/github.com\/angular\/flex-layout\">flex-layout module<\/a> that I am using.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I have been using the Angular Material mat-menu for playlist selection. It&#8217;s Material Design&#8217;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 &#8211; for less scrolling. Also, I wanted a more &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/www.bullcrane.com\/angular\/2018\/07\/12\/a-more-inviting-playlist-picker\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;A more inviting playlist picker&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[5],"tags":[],"_links":{"self":[{"href":"http:\/\/www.bullcrane.com\/angular\/wp-json\/wp\/v2\/posts\/311"}],"collection":[{"href":"http:\/\/www.bullcrane.com\/angular\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.bullcrane.com\/angular\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.bullcrane.com\/angular\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.bullcrane.com\/angular\/wp-json\/wp\/v2\/comments?post=311"}],"version-history":[{"count":19,"href":"http:\/\/www.bullcrane.com\/angular\/wp-json\/wp\/v2\/posts\/311\/revisions"}],"predecessor-version":[{"id":332,"href":"http:\/\/www.bullcrane.com\/angular\/wp-json\/wp\/v2\/posts\/311\/revisions\/332"}],"wp:attachment":[{"href":"http:\/\/www.bullcrane.com\/angular\/wp-json\/wp\/v2\/media?parent=311"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.bullcrane.com\/angular\/wp-json\/wp\/v2\/categories?post=311"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.bullcrane.com\/angular\/wp-json\/wp\/v2\/tags?post=311"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}