Skip to content

Commit

Permalink
fix(material/slider): handle ngModel initial null value (#27149)
Browse files Browse the repository at this point in the history
* fix(material/slider): handle ngModel initial null value

* fixes yaqs/6342072129453817856

* fixup! fix(material/slider): handle ngModel initial null value

* fixup! fix(material/slider): handle ngModel initial null value

* fixup! fix(material/slider): handle ngModel initial null value

* fixup! fix(material/slider): handle ngModel initial null value

* fixup! fix(material/slider): handle ngModel initial null value

* fixup! fix(material/slider): handle ngModel initial null value

* fixup! fix(material/slider): handle ngModel initial null value

* fixup! fix(material/slider): handle ngModel initial null value
  • Loading branch information
wagnermaciel authored May 26, 2023
1 parent 5e1d16c commit 43c6fe3
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 7 deletions.
29 changes: 22 additions & 7 deletions src/material/slider/slider-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,21 @@ export class MatSliderThumb implements _MatSliderThumb, OnDestroy, ControlValueA
_skipUIUpdate: boolean = false;

/** Callback called when the slider input value changes. */
private _onChangeFn: (value: any) => void = () => {};
protected _onChangeFn: ((value: any) => void) | undefined;

/** Callback called when the slider input has been touched. */
private _onTouchedFn: () => void = () => {};

/**
* Whether the NgModel has been initialized.
*
* This flag is used to ignore ghost null calls to
* writeValue which can break slider initialization.
*
* See https://github.com/angular/angular/issues/14988.
*/
protected _isControlInitialized = false;

constructor(
readonly _ngZone: NgZone,
readonly _elementRef: ElementRef<HTMLInputElement>,
Expand Down Expand Up @@ -328,7 +338,7 @@ export class MatSliderThumb implements _MatSliderThumb, OnDestroy, ControlValueA
}

_onInput(): void {
this._onChangeFn(this.value);
this._onChangeFn?.(this.value);
// handles arrowing and updating the value when
// a step is defined.
if (this._slider.step || !this._isActive) {
Expand Down Expand Up @@ -422,7 +432,7 @@ export class MatSliderThumb implements _MatSliderThumb, OnDestroy, ControlValueA

this.value = value;
this.valueChange.emit(this.value);
this._onChangeFn(this.value);
this._onChangeFn?.(this.value);
this._slider._onValueChange(this);
this._slider.step > 0
? this._updateThumbUIByValue()
Expand Down Expand Up @@ -500,7 +510,9 @@ export class MatSliderThumb implements _MatSliderThumb, OnDestroy, ControlValueA
* @docs-private
*/
writeValue(value: any): void {
this.value = value;
if (this._isControlInitialized || value !== null) {
this.value = value;
}
}

/**
Expand All @@ -510,6 +522,7 @@ export class MatSliderThumb implements _MatSliderThumb, OnDestroy, ControlValueA
*/
registerOnChange(fn: any): void {
this._onChangeFn = fn;
this._isControlInitialized = true;
}

/**
Expand Down Expand Up @@ -738,8 +751,10 @@ export class MatSliderRangeThumb extends MatSliderThumb implements _MatSliderRan
* @docs-private
*/
override writeValue(value: any): void {
this.value = value;
this._updateWidthInactive();
this._updateSibling();
if (this._isControlInitialized || value !== null) {
this.value = value;
this._updateWidthInactive();
this._updateSibling();
}
}
}
31 changes: 31 additions & 0 deletions src/material/slider/slider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,21 @@ describe('MDC-based MatSlider', () => {
}));
});

describe('range slider w/ NgModel edge case', () => {
it('should initialize correctly despite NgModel `null` bug', fakeAsync(() => {
const fixture = createComponent(RangeSliderWithNgModelEdgeCase);
fixture.detectChanges();
const sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider));
const slider = sliderDebugElement.componentInstance;
const startInput = slider._getInput(_MatThumb.START) as MatSliderRangeThumb;
const endInput = slider._getInput(_MatThumb.END) as MatSliderRangeThumb;
flush();
console.log('result: ', startInput.value);
checkInput(startInput, {min: -1, max: -0.3, value: -0.7, translateX: 90});
checkInput(endInput, {min: -0.7, max: 0, value: -0.3, translateX: 210});
}));
});

describe('slider as a custom form control', () => {
let fixture: ComponentFixture<SliderWithFormControl>;
let slider: MatSlider;
Expand Down Expand Up @@ -1617,6 +1632,22 @@ class RangeSliderWithNgModel {
endVal: number | undefined = 100;
}

@Component({
template: `
<mat-slider min="-1" max="0" step="0.1">
<input [(ngModel)]="startValue" matSliderStartThumb />
<input [(ngModel)]="endValue" matSliderEndThumb />
</mat-slider>
`,
styles: SLIDER_STYLES,
})
class RangeSliderWithNgModelEdgeCase {
@ViewChild(MatSlider) slider: MatSlider;
startValue: number = -0.7;
endValue: number = -0.3;
}

@Component({
template: `
<mat-slider>
Expand Down
2 changes: 2 additions & 0 deletions tools/public_api_guard/material/slider.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ export class MatSliderThumb implements _MatSliderThumb, OnDestroy, ControlValueA
// (undocumented)
_initValue(): void;
_isActive: boolean;
protected _isControlInitialized: boolean;
_isFocused: boolean;
_knobRadius: number;
get max(): number;
Expand All @@ -232,6 +233,7 @@ export class MatSliderThumb implements _MatSliderThumb, OnDestroy, ControlValueA
_onBlur(): void;
// (undocumented)
_onChange(): void;
protected _onChangeFn: ((value: any) => void) | undefined;
// (undocumented)
_onFocus(): void;
// (undocumented)
Expand Down

0 comments on commit 43c6fe3

Please sign in to comment.