Skip to content

Commit d01c58c

Browse files
crisbetojelbourn
authored andcommitted
feat(slider): add the ability to apply custom formatting to thumb label (#10243)
Adds the `displayWith` input on the slider that allows consumers to specify how the thumb label will be formatting. This is useful for cases like very large numbers where the number might be too long for the thumb label. Fixes #9431.
1 parent 583fe15 commit d01c58c

File tree

6 files changed

+105
-2
lines changed

6 files changed

+105
-2
lines changed

src/lib/slider/slider.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
`<mat-slider>` allows for the selection of a value from a range via mouse, touch, or keyboard,
1+
`<mat-slider>` allows for the selection of a value from a range via mouse, touch, or keyboard,
22
similar to `<input type="range">`.
33

44
<!-- example(slider-overview) -->
@@ -27,7 +27,7 @@ on bottom and the maximum value on top.
2727

2828
An `invert` attribute is also available which can be specified to flip the axis that the thumb moves
2929
along. An inverted horizontal slider will have the minimum value on the right and the maximum value
30-
on the left, while an inverted vertical slider will have the minimum value on top and the maximum
30+
on the left, while an inverted vertical slider will have the minimum value on top and the maximum
3131
value on bottom.
3232

3333
```html
@@ -46,6 +46,13 @@ discrete value (such as a 1-5 rating).
4646
<mat-slider thumbLabel tickInterval="1"></mat-slider>
4747
```
4848

49+
### Formatting the thumb label
50+
By default, the value in the slider's thumb label will be the same as the model value, however this
51+
may end up being too large to fit into the label. If you want to control the value that is being
52+
displayed, you can do so using the `displayWith` input.
53+
54+
<!-- example(slider-formatting) -->
55+
4956
### Tick marks
5057
By default, sliders do not show tick marks along the thumb track. This can be enabled using the
5158
`tickInterval` attribute. The value of `tickInterval` should be a number representing the number

src/lib/slider/slider.spec.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ describe('MatSlider without forms', () => {
4242
SliderWithTabIndexBinding,
4343
SliderWithNativeTabindexAttr,
4444
VerticalSlider,
45+
SliderWithCustomThumbLabelFormatting,
4546
],
4647
providers: [
4748
{provide: HAMMER_GESTURE_CONFIG, useFactory: () => {
@@ -602,6 +603,38 @@ describe('MatSlider without forms', () => {
602603
});
603604
});
604605

606+
describe('slider with custom thumb label formatting', () => {
607+
let fixture: ComponentFixture<SliderWithCustomThumbLabelFormatting>;
608+
let sliderInstance: MatSlider;
609+
let thumbLabelTextElement: Element;
610+
611+
beforeEach(() => {
612+
fixture = TestBed.createComponent(SliderWithCustomThumbLabelFormatting);
613+
fixture.detectChanges();
614+
615+
const sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider));
616+
const sliderNativeElement = sliderDebugElement.nativeElement;
617+
sliderInstance = sliderDebugElement.componentInstance;
618+
thumbLabelTextElement = sliderNativeElement.querySelector('.mat-slider-thumb-label-text')!;
619+
});
620+
621+
it('should invoke the passed-in `displayWith` function with the value', () => {
622+
spyOn(fixture.componentInstance, 'displayWith').and.callThrough();
623+
624+
sliderInstance.value = 1337;
625+
fixture.detectChanges();
626+
627+
expect(fixture.componentInstance.displayWith).toHaveBeenCalledWith(1337);
628+
});
629+
630+
it('should format the thumb label based on the passed-in `displayWith` function', () => {
631+
sliderInstance.value = 200000;
632+
fixture.detectChanges();
633+
634+
expect(thumbLabelTextElement.textContent).toBe('200k');
635+
});
636+
});
637+
605638
describe('slider with value property binding', () => {
606639
let fixture: ComponentFixture<SliderWithOneWayBinding>;
607640
let sliderDebugElement: DebugElement;
@@ -1426,6 +1459,26 @@ class SliderWithSetTickInterval {
14261459
})
14271460
class SliderWithThumbLabel { }
14281461

1462+
1463+
@Component({
1464+
template: `<mat-slider min="1" max="100000" [displayWith]="displayWith" thumbLabel></mat-slider>`,
1465+
styles: [styles],
1466+
})
1467+
class SliderWithCustomThumbLabelFormatting {
1468+
displayWith(value: number | null) {
1469+
if (!value) {
1470+
return 0;
1471+
}
1472+
1473+
if (value >= 1000) {
1474+
return (value / 1000) + 'k';
1475+
}
1476+
1477+
return value;
1478+
}
1479+
}
1480+
1481+
14291482
@Component({
14301483
template: `<mat-slider [value]="val"></mat-slider>`,
14311484
styles: [styles],

src/lib/slider/slider.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,13 @@ export class MatSlider extends _MatSliderMixinBase
247247
}
248248
private _value: number | null = null;
249249

250+
/**
251+
* Function that will be used to format the value before it is displayed
252+
* in the thumb label. Can be used to format very large number in order
253+
* for them to fit into the slider thumb.
254+
*/
255+
@Input() displayWith: (value: number | null) => string | number;
256+
250257
/** Whether the slider is vertical. */
251258
@Input()
252259
get vertical(): boolean { return this._vertical; }
@@ -263,6 +270,10 @@ export class MatSlider extends _MatSliderMixinBase
263270

264271
/** The value to be used for display purposes. */
265272
get displayValue(): string | number {
273+
if (this.displayWith) {
274+
return this.displayWith(this.value);
275+
}
276+
266277
// Note that this could be improved further by rounding something like 0.999 to 1 or
267278
// 0.899 to 0.9, however it is very performance sensitive, because it gets called on
268279
// every change detection cycle.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mat-slider {
2+
width: 300px;
3+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<mat-slider
2+
thumbLabel
3+
[displayWith]="formatLabel"
4+
tickInterval="1000"
5+
min="1"
6+
max="100000"></mat-slider>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {Component} from '@angular/core';
2+
3+
/**
4+
* @title Slider with custom thumb label formatting.
5+
*/
6+
@Component({
7+
selector: 'slider-formatting-example',
8+
templateUrl: 'slider-formatting-example.html',
9+
styleUrls: ['slider-formatting-example.css'],
10+
})
11+
export class SliderFormattingExample {
12+
formatLabel(value: number | null) {
13+
if (!value) {
14+
return 0;
15+
}
16+
17+
if (value >= 1000) {
18+
return Math.round(value / 1000) + 'k';
19+
}
20+
21+
return value;
22+
}
23+
}

0 commit comments

Comments
 (0)