Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 6.8k
feat(select): add md-select-header directive#3211
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
24203986df224b57534ae498c5696f6297eFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -113,5 +113,20 @@ | ||
| </md-card> | ||
| </div> | ||
| <md-card *ngIf="showSelect"> | ||
| <md-select placeholder="Drink" [(ngModel)]="currentDrink" #selectWitHeader="mdSelect"> | ||
| <md-select-header> | ||
| <input type="search" [(ngModel)]="searchTerm" role="combobox" [attr.aria-owns]="selectWitHeader.panelId" | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you try this out in a screen reader w/ this role/aria-owns? I'm not sure it will work as expected | ||
| (ngModelChange)="filterDrinks()" placeholder="Search for a drink"/> | ||
| </md-select-header> | ||
| <md-option *ngFor="let drink of filteredDrinks" [value]="drink.value" [disabled]="drink.disabled"> | ||
| {{ drink.viewValue }} | ||
| </md-option> | ||
| </md-select> | ||
| </md-card> | ||
| </div> | ||
| <div style="height: 500px">This div is for testing scrolled selects.</div> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| /** No CSS for this example */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <md-select placeholder="Favorite food" [(ngModel)]="selectedValue" name="food" #select="mdSelect"> | ||
| <md-select-header> | ||
| <input type="search" [(ngModel)]="searchString" role="combobox" [attr.aria-owns]="select.panelId" | ||
| (ngModelChange)="filterFoods()" placeholder="Search for food"/> | ||
| </md-select-header> | ||
| <md-option *ngFor="let food of foods" [value]="food.value"> | ||
| {{food.viewValue}} | ||
| </md-option> | ||
| </md-select> | ||
| <p> Selected value: {{selectedValue}} </p> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import {Component} from '@angular/core'; | ||
| @Component({ | ||
| selector: 'select-form-example', | ||
| templateUrl: './select-form-example.html', | ||
| }) | ||
| export class SelectHeaderExample { | ||
| selectedValue: string; | ||
| searchString: string; | ||
| initialFoods = [ | ||
| { value: 'steak-0', viewValue: 'Steak' }, | ||
| { value: 'pizza-1', viewValue: 'Pizza' }, | ||
| { value: 'tacos-2', viewValue: 'Tacos' }, | ||
| { value: 'sandwich-3', viewValue: 'Sandwich' }, | ||
| { value: 'chips-4', viewValue: 'Chips' }, | ||
| { value: 'eggs-5', viewValue: 'Eggs' }, | ||
| { value: 'pasta-6', viewValue: 'Pasta' }, | ||
| { value: 'sushi-7', viewValue: 'Sushi' }, | ||
| ]; | ||
| foods = this.initialFoods.slice(); | ||
| filterFoods() { | ||
| this.foods = this.searchString ? this.initialFoods.filter(item => { | ||
| return item.viewValue.toLowerCase().indexOf(this.searchString.toLowerCase()) > -1; | ||
| }) : this.initialFoods.slice(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| /** | ||
| * @license | ||
| * Copyright Google Inc. All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.io/license | ||
| */ | ||
| import {Directive} from '@angular/core'; | ||
| /** | ||
| * Fixed header that will be rendered above a select's options. | ||
| */ | ||
| @Directive({ | ||
| selector: 'md-select-header, mat-select-header', | ||
| host: { | ||
| 'class': 'mat-select-header', | ||
| } | ||
| }) | ||
| export class MdSelectHeader { } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -35,7 +35,12 @@ | ||
| [style.transformOrigin]="_transformOrigin" | ||
| [class.mat-select-panel-done-animating]="_panelDoneAnimating"> | ||
| <div class="mat-select-content" [@fadeInContent]="'showing'" (@fadeInContent.done)="_onFadeInDone()"> | ||
| <div [@fadeInContent]="'showing'"> | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you could replace this | ||
| <ng-content select="md-select-header, mat-select-header"></ng-content> | ||
| </div> | ||
| <div class="mat-select-content" [attr.id]="panelId" [@fadeInContent]="'showing'" | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think just | ||
| (@fadeInContent.done)="_onFadeInDone()"> | ||
| <ng-content></ng-content> | ||
| </div> | ||
| </div> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -117,14 +117,33 @@ $mat-select-panel-max-height: 256px !default; | ||
| margin: 0 $mat-select-arrow-margin; | ||
| } | ||
| .mat-select-panel { | ||
| @include mat-menu-base(); | ||
| padding-top: 0; | ||
| padding-bottom: 0; | ||
| .mat-select-content { | ||
| @include mat-menu-scrollable(); | ||
| max-height: $mat-select-panel-max-height; | ||
| min-width: 100%; // prevents some animation twitching and test inconsistencies in IE11 | ||
| @include cdk-high-contrast { | ||
| outline: solid 1px; | ||
| } | ||
| } | ||
| .mat-select-panel { | ||
| @include mat-menu-base(); | ||
| border: none; | ||
| } | ||
| .mat-select-header { | ||
| @include mat-menu-item-base(); | ||
| border-bottom: solid 1px; | ||
| box-sizing: border-box; | ||
| input { | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd lean toward omitting this style in the select itself, since the select header is mean to be a generic container that's not necessarily used for this style of filter (even if that is the most common use case)
| ||
| display: block; | ||
| width: 100%; | ||
| height: 100%; | ||
| border: none; | ||
| outline: none; | ||
| padding: 0; | ||
| background: transparent; | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this demo, if I select a value and then try to type into the input then the focus leaves the text input on every keypress
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm you're right. This complicates things a lot, because it means that we'd need two different key handling strategies depending on whether the select has a header (
FocusKeyManagerby default andActiveDescendantKeyManagerif there's a header), which in turn will complicate the select even more, because it would have to delegate to the header in some cases but not in others. I can see how it can turn into a huge mess pretty quickly since we'd need to sprinkleif (this.header)all over the place and there would be aMdSelect <-> MdSelectHeaderdependency. It might be best if we park and rethink whether we want to do this or recommend that people usemd-autocompleteinstead.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just not this, please, searching is not the sole use case for the select header and even if it was, autocomplete has it's own problems that make it hard to use as a select.. #3334