Skip to content

feat(material-experimental/mdc-slider): implement control value accessor #22016

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 1, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 71 additions & 3 deletions src/material-experimental/mdc-slider/slider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
ViewChildren,
ViewEncapsulation,
} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
import {
CanColorCtor,
MatRipple,
Expand Down Expand Up @@ -249,11 +250,16 @@ export class MatSliderVisualThumb implements AfterViewInit, OnDestroy {
host: {
'class': 'mdc-slider__input',
'type': 'range',
'(blur)': '_blur.emit()',
'(blur)': '_onBlur()',
'(focus)': '_focus.emit()',
},
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: MatSliderThumb,
multi: true
}],
})
export class MatSliderThumb implements AfterViewInit {
export class MatSliderThumb implements AfterViewInit, ControlValueAccessor {

// ** IMPORTANT NOTE **
//
Expand Down Expand Up @@ -298,6 +304,20 @@ export class MatSliderThumb implements AfterViewInit {
/** Event emitted every time the MatSliderThumb is focused. */
@Output() readonly _focus: EventEmitter<void> = new EventEmitter<void>();

_disabled: boolean = false;

/**
* A callback function that is called when the
* control's value changes in the UI (ControlValueAccessor).
*/
_onChange: (value: any) => void = () => {};

/**
* A callback function that is called by the forms API on
* initialization to update the form model on blur (ControlValueAccessor).
*/
private _onTouched: () => void = () => {};

/** Indicates which slider thumb this input corresponds to. */
_thumbPosition: Thumb = this._elementRef.nativeElement.hasAttribute('matSliderStartThumb')
? Thumb.START
Expand Down Expand Up @@ -331,6 +351,47 @@ export class MatSliderThumb implements AfterViewInit {
}
}

_onBlur(): void {
this._onTouched();
this._blur.emit();
}

/**
* Sets the model value. Implemented as part of ControlValueAccessor.
* @param value
*/
writeValue(value: any): void {
this.value = value;
}

/**
* Registers a callback to be triggered when the value has changed.
* Implemented as part of ControlValueAccessor.
* @param fn Callback to be registered.
*/
registerOnChange(fn: any): void {
this._onChange = fn;
}

/**
* Registers a callback to be triggered when the component is touched.
* Implemented as part of ControlValueAccessor.
* @param fn Callback to be registered.
*/
registerOnTouched(fn: any): void {
this._onTouched = fn;
}

/**
* Sets whether the component should be disabled.
* Implemented as part of ControlValueAccessor.
* @param isDisabled
*/
setDisabledState(isDisabled: boolean): void {
this._disabled = isDisabled;
this._slider._updateDisabled();
}

/** Returns true if this slider input currently has focus. */
_isFocused(): boolean {
return this._document.activeElement === this._hostElement;
Expand Down Expand Up @@ -562,6 +623,11 @@ export class MatSlider extends _MatSliderMixinBase implements AfterViewInit, OnD
return this._inputs.length === 2;
}

/** Sets the disabled state based on the disabled state of the inputs (ControlValueAccessor). */
_updateDisabled(): void {
this.disabled = this._inputs.some(input => input._disabled);
}

/** Gets the slider thumb input of the given thumb position. */
_getInput(thumbPosition: Thumb): MatSliderThumb {
return thumbPosition === Thumb.END ? this._inputs.last : this._inputs.first;
Expand Down Expand Up @@ -709,7 +775,9 @@ class SliderAdapter implements MDCSliderAdapter {
}
// We ignore emitChangeEvent and emitInputEvent because the slider inputs
// are already exposed so users can just listen for those events directly themselves.
emitChangeEvent = (value: number, thumbPosition: Thumb): void => {};
emitChangeEvent = (value: number, thumbPosition: Thumb): void => {
this._delegate._getInput(thumbPosition)._onChange(value);
}
emitInputEvent = (value: number, thumbPosition: Thumb): void => {};
emitDragStartEvent = (value: number, thumbPosition: Thumb): void => {
const input = this._delegate._getInput(thumbPosition);
Expand Down