diff --git a/src/examples/example-module.ts b/src/examples/example-module.ts index 60293aeb56ff..f6a06509c251 100644 --- a/src/examples/example-module.ts +++ b/src/examples/example-module.ts @@ -66,6 +66,7 @@ import {TabsTemplateLabelExample} from './tabs-template-label/tabs-template-labe import {RadioOverviewExample} from './radio-overview/radio-overview-example'; import {SidenavOverviewExample} from './sidenav-overview/sidenav-overview-example'; import {SelectOverviewExample} from './select-overview/select-overview-example'; +import {SelectLabelExample} from './select-label/select-label-example'; import {ChipsOverviewExample} from './chips-overview/chips-overview-example'; import {ChipsStackedExample} from './chips-stacked/chips-stacked-example'; import {SelectFormExample} from './select-form/select-form-example'; @@ -141,6 +142,7 @@ export const EXAMPLE_COMPONENTS = { 'radio-ng-model': {title: 'Radios with ngModel', component: RadioNgModelExample}, 'radio-overview': {title: 'Basic radios', component: RadioOverviewExample}, 'select-overview': {title: 'Basic select', component: SelectOverviewExample}, + 'select-label': {title: 'Select with custom label', component: SelectLabelExample}, 'select-form': {title: 'Select in a form', component: SelectFormExample}, 'sidenav-fab': {title: 'Sidenav with a FAB', component: SidenavFabExample}, 'sidenav-overview': {title: 'Basic sidenav', component: SidenavOverviewExample}, @@ -203,6 +205,7 @@ export const EXAMPLE_LIST = [ RadioOverviewExample, SidenavFabExample, SelectOverviewExample, + SelectLabelExample, SelectFormExample, SidenavOverviewExample, SliderConfigurableExample, diff --git a/src/examples/select-label/select-label-example.css b/src/examples/select-label/select-label-example.css new file mode 100644 index 000000000000..7432308753e6 --- /dev/null +++ b/src/examples/select-label/select-label-example.css @@ -0,0 +1 @@ +/** No CSS for this example */ diff --git a/src/examples/select-label/select-label-example.html b/src/examples/select-label/select-label-example.html new file mode 100644 index 000000000000..6bf6c39a4237 --- /dev/null +++ b/src/examples/select-label/select-label-example.html @@ -0,0 +1,6 @@ + + You have selected: {{ select.selected?.viewValue }} + + {{ food.viewValue }} + + diff --git a/src/examples/select-label/select-label-example.ts b/src/examples/select-label/select-label-example.ts new file mode 100644 index 000000000000..fc35a273a84e --- /dev/null +++ b/src/examples/select-label/select-label-example.ts @@ -0,0 +1,14 @@ +import {Component} from '@angular/core'; + + +@Component({ + selector: 'select-label-example', + templateUrl: './select-label-example.html', +}) +export class SelectLabelExample { + foods = [ + {value: 'steak-0', viewValue: 'Steak'}, + {value: 'pizza-1', viewValue: 'Pizza'}, + {value: 'tacos-2', viewValue: 'Tacos'} + ]; +} diff --git a/src/lib/select/index.ts b/src/lib/select/index.ts index 1a2e4afe6a88..0a76d2ddf482 100644 --- a/src/lib/select/index.ts +++ b/src/lib/select/index.ts @@ -1,19 +1,21 @@ import {NgModule, ModuleWithProviders} from '@angular/core'; import {CommonModule} from '@angular/common'; import {MdSelect} from './select'; +import {MdSelectLabel} from './select-label'; import {MdOptionModule} from '../core/option/option'; import { CompatibilityModule, OverlayModule, } from '../core'; export * from './select'; +export * from './select-label'; export {fadeInContent, transformPanel, transformPlaceholder} from './select-animations'; @NgModule({ imports: [CommonModule, OverlayModule, MdOptionModule, CompatibilityModule], - exports: [MdSelect, MdOptionModule, CompatibilityModule], - declarations: [MdSelect], + exports: [MdSelect, MdSelectLabel, MdOptionModule, CompatibilityModule], + declarations: [MdSelect, MdSelectLabel], }) export class MdSelectModule { /** @deprecated */ diff --git a/src/lib/select/select-label.ts b/src/lib/select/select-label.ts new file mode 100644 index 000000000000..79cbcbd8f5f6 --- /dev/null +++ b/src/lib/select/select-label.ts @@ -0,0 +1,9 @@ +import {Directive} from '@angular/core'; + +/** + * Allows the user to customize the label that is displayed `md-select` has a value. + */ +@Directive({ + selector: 'md-select-label, mat-select-label' +}) +export class MdSelectLabel { } diff --git a/src/lib/select/select.html b/src/lib/select/select.html index d3ae2a6ca256..953106d35f72 100644 --- a/src/lib/select/select.html +++ b/src/lib/select/select.html @@ -6,7 +6,10 @@ [style.visibility]="_getPlaceholderVisibility()" [style.width.px]="_selectedValueWidth"> {{ placeholder }} - {{ selected?.viewValue }} + + + {{ selected?.viewValue }} + diff --git a/src/lib/select/select.spec.ts b/src/lib/select/select.spec.ts index 63e1f8f848f6..e83c1ec17318 100644 --- a/src/lib/select/select.spec.ts +++ b/src/lib/select/select.spec.ts @@ -39,7 +39,8 @@ describe('MdSelect', () => { FloatPlaceholderSelect, SelectWithErrorSibling, ThrowsErrorOnInit, - BasicSelectOnPush + BasicSelectOnPush, + SelectWithCustomLabel ], providers: [ {provide: OverlayContainer, useFactory: () => { @@ -579,7 +580,6 @@ describe('MdSelect', () => { }); - describe('animations', () => { let fixture: ComponentFixture; let trigger: HTMLElement; @@ -1253,6 +1253,19 @@ describe('MdSelect', () => { }).toThrowError(new RegExp('Oh no!', 'g')); })); + it('should allow the user to customize the label', () => { + const fixture = TestBed.createComponent(SelectWithCustomLabel); + fixture.detectChanges(); + + fixture.componentInstance.control.setValue('pizza-1'); + fixture.detectChanges(); + + const label = fixture.debugElement.query(By.css('.mat-select-value')).nativeElement; + + expect(label.textContent).toContain('azziP', + 'Expected the displayed text to be "Pizza" in reverse.'); + }); + }); describe('change event', () => { @@ -1343,6 +1356,7 @@ describe('MdSelect', () => { expect(trigger.textContent).not.toContain('Pizza'); }); }); + }); @@ -1589,6 +1603,26 @@ class FloatPlaceholderSelect { @ViewChild(MdSelect) select: MdSelect; } +@Component({ + selector: 'select-with-custom-label', + template: ` + + + {{ select.selected?.viewValue.split('').reverse().join('') }} + + + {{ food.viewValue }} + + + ` +}) +class SelectWithCustomLabel { + foods: any[] = [ + { value: 'steak-0', viewValue: 'Steak' }, + { value: 'pizza-1', viewValue: 'Pizza' }, + ]; + control = new FormControl(); +} class FakeViewportRuler { getViewportRect() { diff --git a/src/lib/select/select.ts b/src/lib/select/select.ts index 1a92699e5437..c476fafc1381 100644 --- a/src/lib/select/select.ts +++ b/src/lib/select/select.ts @@ -1,6 +1,7 @@ import { AfterContentInit, Component, + ContentChild, ContentChildren, ElementRef, EventEmitter, @@ -25,6 +26,7 @@ import {ControlValueAccessor, NgControl} from '@angular/forms'; import {coerceBooleanProperty} from '../core/coercion/boolean-property'; import {ConnectedOverlayDirective} from '../core/overlay/overlay-directives'; import {ViewportRuler} from '../core/overlay/position/viewport-ruler'; +import {MdSelectLabel} from './select-label'; import 'rxjs/add/operator/startWith'; @@ -207,6 +209,9 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr /** All of the defined select options. */ @ContentChildren(MdOption) options: QueryList; + /** User-supplied override of the selected value label. */ + @ContentChild(MdSelectLabel) customLabel: MdSelectLabel; + /** Placeholder to be shown if no value has been selected. */ @Input() get placeholder() { return this._placeholder; }