Skip to content

Commit

Permalink
feat(select): add ability to customize the selected value label
Browse files Browse the repository at this point in the history
Adds the `md-select-label` directive which allows users to customize the selected value. E.g. it is now possible to do something like this, if the user wanted to reverse the selected label for some reason:

```ts
<md-select placeholder="Food" [formControl]="control" #select="mdSelect">
  <md-select-label>
    {{ select.selected?.viewValue.split('').reverse().join('') }}
  </md-select-label>
  <md-option *ngFor="let food of foods" [value]="food.value">
    {{ food.viewValue }}
  </md-option>
</md-select>
```

Fixes #2275.
  • Loading branch information
crisbeto committed Feb 28, 2017
1 parent d1abc9e commit 4be049b
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 5 deletions.
3 changes: 3 additions & 0 deletions src/examples/example-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -203,6 +205,7 @@ export const EXAMPLE_LIST = [
RadioOverviewExample,
SidenavFabExample,
SelectOverviewExample,
SelectLabelExample,
SelectFormExample,
SidenavOverviewExample,
SliderConfigurableExample,
Expand Down
1 change: 1 addition & 0 deletions src/examples/select-label/select-label-example.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** No CSS for this example */
6 changes: 6 additions & 0 deletions src/examples/select-label/select-label-example.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<md-select placeholder="Favorite food" #select="mdSelect">
<md-select-label>You have selected: {{ select.selected?.viewValue }}</md-select-label>
<md-option *ngFor="let food of foods" [value]="food.value">
{{ food.viewValue }}
</md-option>
</md-select>
14 changes: 14 additions & 0 deletions src/examples/select-label/select-label-example.ts
Original file line number Diff line number Diff line change
@@ -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'}
];
}
6 changes: 4 additions & 2 deletions src/lib/select/index.ts
Original file line number Diff line number Diff line change
@@ -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 */
Expand Down
9 changes: 9 additions & 0 deletions src/lib/select/select-label.ts
Original file line number Diff line number Diff line change
@@ -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 { }
5 changes: 4 additions & 1 deletion src/lib/select/select.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
[style.visibility]="_getPlaceholderVisibility()"
[style.width.px]="_selectedValueWidth"> {{ placeholder }} </span>
<span class="mat-select-value" *ngIf="selected">
<span class="mat-select-value-text">{{ selected?.viewValue }}</span>
<span class="mat-select-value-text" [ngSwitch]="!!customLabel">
<ng-content select="md-select-label, mat-select-label" *ngSwitchCase="true"></ng-content>
<span *ngSwitchDefault>{{ selected?.viewValue }}</span>
</span>
</span>

<span class="mat-select-arrow"></span>
Expand Down
38 changes: 36 additions & 2 deletions src/lib/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ describe('MdSelect', () => {
FloatPlaceholderSelect,
SelectWithErrorSibling,
ThrowsErrorOnInit,
BasicSelectOnPush
BasicSelectOnPush,
SelectWithCustomLabel
],
providers: [
{provide: OverlayContainer, useFactory: () => {
Expand Down Expand Up @@ -579,7 +580,6 @@ describe('MdSelect', () => {

});


describe('animations', () => {
let fixture: ComponentFixture<BasicSelect>;
let trigger: HTMLElement;
Expand Down Expand Up @@ -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', () => {
Expand Down Expand Up @@ -1343,6 +1356,7 @@ describe('MdSelect', () => {
expect(trigger.textContent).not.toContain('Pizza');
});
});

});


Expand Down Expand Up @@ -1589,6 +1603,26 @@ class FloatPlaceholderSelect {
@ViewChild(MdSelect) select: MdSelect;
}

@Component({
selector: 'select-with-custom-label',
template: `
<md-select placeholder="Food" [formControl]="control" #select="mdSelect">
<md-select-label>
{{ select.selected?.viewValue.split('').reverse().join('') }}
</md-select-label>
<md-option *ngFor="let food of foods" [value]="food.value">
{{ food.viewValue }}
</md-option>
</md-select>
`
})
class SelectWithCustomLabel {
foods: any[] = [
{ value: 'steak-0', viewValue: 'Steak' },
{ value: 'pizza-1', viewValue: 'Pizza' },
];
control = new FormControl();
}

class FakeViewportRuler {
getViewportRect() {
Expand Down
5 changes: 5 additions & 0 deletions src/lib/select/select.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
AfterContentInit,
Component,
ContentChild,
ContentChildren,
ElementRef,
EventEmitter,
Expand All @@ -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';


Expand Down Expand Up @@ -207,6 +209,9 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
/** All of the defined select options. */
@ContentChildren(MdOption) options: QueryList<MdOption>;

/** 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; }
Expand Down

0 comments on commit 4be049b

Please sign in to comment.