diff --git a/src/lib/slider/slider.md b/src/lib/slider/slider.md index 9c0dac948c6..9e55a72a7ee 100644 --- a/src/lib/slider/slider.md +++ b/src/lib/slider/slider.md @@ -1,4 +1,4 @@ -`` allows for the selection of a value from a range via mouse, touch, or keyboard, +`` allows for the selection of a value from a range via mouse, touch, or keyboard, similar to ``. @@ -27,7 +27,7 @@ on bottom and the maximum value on top. An `invert` attribute is also available which can be specified to flip the axis that the thumb moves along. An inverted horizontal slider will have the minimum value on the right and the maximum value -on the left, while an inverted vertical slider will have the minimum value on top and the maximum +on the left, while an inverted vertical slider will have the minimum value on top and the maximum value on bottom. ```html @@ -46,6 +46,13 @@ discrete value (such as a 1-5 rating). ``` +### Formatting the thumb label +By default, the value in the slider's thumb label will be the same as the model value, however this +may end up being too large to fit into the label. If you want to control the value that is being +displayed, you can do so using the `displayWith` input. + + + ### Tick marks By default, sliders do not show tick marks along the thumb track. This can be enabled using the `tickInterval` attribute. The value of `tickInterval` should be a number representing the number diff --git a/src/lib/slider/slider.spec.ts b/src/lib/slider/slider.spec.ts index c9085b79187..ce00bfe0ddc 100644 --- a/src/lib/slider/slider.spec.ts +++ b/src/lib/slider/slider.spec.ts @@ -42,6 +42,7 @@ describe('MatSlider without forms', () => { SliderWithTabIndexBinding, SliderWithNativeTabindexAttr, VerticalSlider, + SliderWithCustomThumbLabelFormatting, ], providers: [ {provide: HAMMER_GESTURE_CONFIG, useFactory: () => { @@ -602,6 +603,38 @@ describe('MatSlider without forms', () => { }); }); + describe('slider with custom thumb label formatting', () => { + let fixture: ComponentFixture; + let sliderInstance: MatSlider; + let thumbLabelTextElement: Element; + + beforeEach(() => { + fixture = TestBed.createComponent(SliderWithCustomThumbLabelFormatting); + fixture.detectChanges(); + + const sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); + const sliderNativeElement = sliderDebugElement.nativeElement; + sliderInstance = sliderDebugElement.componentInstance; + thumbLabelTextElement = sliderNativeElement.querySelector('.mat-slider-thumb-label-text')!; + }); + + it('should invoke the passed-in `displayWith` function with the value', () => { + spyOn(fixture.componentInstance, 'displayWith').and.callThrough(); + + sliderInstance.value = 1337; + fixture.detectChanges(); + + expect(fixture.componentInstance.displayWith).toHaveBeenCalledWith(1337); + }); + + it('should format the thumb label based on the passed-in `displayWith` function', () => { + sliderInstance.value = 200000; + fixture.detectChanges(); + + expect(thumbLabelTextElement.textContent).toBe('200k'); + }); + }); + describe('slider with value property binding', () => { let fixture: ComponentFixture; let sliderDebugElement: DebugElement; @@ -1426,6 +1459,26 @@ class SliderWithSetTickInterval { }) class SliderWithThumbLabel { } + +@Component({ + template: ``, + styles: [styles], +}) +class SliderWithCustomThumbLabelFormatting { + displayWith(value: number | null) { + if (!value) { + return 0; + } + + if (value >= 1000) { + return (value / 1000) + 'k'; + } + + return value; + } +} + + @Component({ template: ``, styles: [styles], diff --git a/src/lib/slider/slider.ts b/src/lib/slider/slider.ts index 6ab64bddca8..4c1aca052de 100644 --- a/src/lib/slider/slider.ts +++ b/src/lib/slider/slider.ts @@ -247,6 +247,13 @@ export class MatSlider extends _MatSliderMixinBase } private _value: number | null = null; + /** + * Function that will be used to format the value before it is displayed + * in the thumb label. Can be used to format very large number in order + * for them to fit into the slider thumb. + */ + @Input() displayWith: (value: number | null) => string | number; + /** Whether the slider is vertical. */ @Input() get vertical(): boolean { return this._vertical; } @@ -263,6 +270,10 @@ export class MatSlider extends _MatSliderMixinBase /** The value to be used for display purposes. */ get displayValue(): string | number { + if (this.displayWith) { + return this.displayWith(this.value); + } + // Note that this could be improved further by rounding something like 0.999 to 1 or // 0.899 to 0.9, however it is very performance sensitive, because it gets called on // every change detection cycle. diff --git a/src/material-examples/slider-formatting/slider-formatting-example.css b/src/material-examples/slider-formatting/slider-formatting-example.css new file mode 100644 index 00000000000..a7b85e100b3 --- /dev/null +++ b/src/material-examples/slider-formatting/slider-formatting-example.css @@ -0,0 +1,3 @@ +mat-slider { + width: 300px; +} diff --git a/src/material-examples/slider-formatting/slider-formatting-example.html b/src/material-examples/slider-formatting/slider-formatting-example.html new file mode 100644 index 00000000000..4cf20026eff --- /dev/null +++ b/src/material-examples/slider-formatting/slider-formatting-example.html @@ -0,0 +1,6 @@ + diff --git a/src/material-examples/slider-formatting/slider-formatting-example.ts b/src/material-examples/slider-formatting/slider-formatting-example.ts new file mode 100644 index 00000000000..3e03dc336b5 --- /dev/null +++ b/src/material-examples/slider-formatting/slider-formatting-example.ts @@ -0,0 +1,23 @@ +import {Component} from '@angular/core'; + +/** + * @title Slider with custom thumb label formatting. + */ +@Component({ + selector: 'slider-formatting-example', + templateUrl: 'slider-formatting-example.html', + styleUrls: ['slider-formatting-example.css'], +}) +export class SliderFormattingExample { + formatLabel(value: number | null) { + if (!value) { + return 0; + } + + if (value >= 1000) { + return Math.round(value / 1000) + 'k'; + } + + return value; + } +}