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.
This commit is contained in:
Kristiyan Kostadinov
2018-03-06 10:42:15 -05:00
committed by Jeremy Elbourn
parent 583fe151fd
commit d01c58c33c
6 changed files with 105 additions and 2 deletions
+9 -2
View File
@@ -1,4 +1,4 @@
`<mat-slider>` allows for the selection of a value from a range via mouse, touch, or keyboard,
`<mat-slider>` allows for the selection of a value from a range via mouse, touch, or keyboard,
similar to `<input type="range">`.
<!-- example(slider-overview) -->
@@ -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).
<mat-slider thumbLabel tickInterval="1"></mat-slider>
```
### 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.
<!-- example(slider-formatting) -->
### 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
+53
View File
@@ -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<SliderWithCustomThumbLabelFormatting>;
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<SliderWithOneWayBinding>;
let sliderDebugElement: DebugElement;
@@ -1426,6 +1459,26 @@ class SliderWithSetTickInterval {
})
class SliderWithThumbLabel { }
@Component({
template: `<mat-slider min="1" max="100000" [displayWith]="displayWith" thumbLabel></mat-slider>`,
styles: [styles],
})
class SliderWithCustomThumbLabelFormatting {
displayWith(value: number | null) {
if (!value) {
return 0;
}
if (value >= 1000) {
return (value / 1000) + 'k';
}
return value;
}
}
@Component({
template: `<mat-slider [value]="val"></mat-slider>`,
styles: [styles],
+11
View File
@@ -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.
@@ -0,0 +1,3 @@
mat-slider {
width: 300px;
}
@@ -0,0 +1,6 @@
<mat-slider
thumbLabel
[displayWith]="formatLabel"
tickInterval="1000"
min="1"
max="100000"></mat-slider>
@@ -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;
}
}