mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(slider): emit input event when slider thumb moves (#2325)
Closes #2296
This commit is contained in:
@@ -785,6 +785,55 @@ describe('MdSlider', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('slider with input event', () => {
|
||||
let fixture: ComponentFixture<SliderWithChangeHandler>;
|
||||
let sliderDebugElement: DebugElement;
|
||||
let sliderNativeElement: HTMLElement;
|
||||
let sliderTrackElement: HTMLElement;
|
||||
let testComponent: SliderWithChangeHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SliderWithChangeHandler);
|
||||
fixture.detectChanges();
|
||||
|
||||
testComponent = fixture.debugElement.componentInstance;
|
||||
spyOn(testComponent, 'onInput');
|
||||
spyOn(testComponent, 'onChange');
|
||||
|
||||
sliderDebugElement = fixture.debugElement.query(By.directive(MdSlider));
|
||||
sliderNativeElement = sliderDebugElement.nativeElement;
|
||||
sliderTrackElement = <HTMLElement>sliderNativeElement.querySelector('.md-slider-track');
|
||||
});
|
||||
|
||||
it('should emit an input event while sliding', () => {
|
||||
expect(testComponent.onChange).not.toHaveBeenCalled();
|
||||
|
||||
dispatchMouseenterEvent(sliderNativeElement);
|
||||
dispatchSlideEvent(sliderNativeElement, 0.5, gestureConfig);
|
||||
dispatchSlideEvent(sliderNativeElement, 1, gestureConfig);
|
||||
dispatchSlideEndEvent(sliderNativeElement, 1, gestureConfig);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
// The input event should fire twice, because the slider changed two times.
|
||||
expect(testComponent.onInput).toHaveBeenCalledTimes(2);
|
||||
expect(testComponent.onChange).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should emit an input event when clicking', () => {
|
||||
expect(testComponent.onChange).not.toHaveBeenCalled();
|
||||
|
||||
dispatchClickEventSequence(sliderNativeElement, 0.75);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
// The `onInput` event should be emitted once due to a single click.
|
||||
expect(testComponent.onInput).toHaveBeenCalledTimes(1);
|
||||
expect(testComponent.onChange).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('keyboard support', () => {
|
||||
let fixture: ComponentFixture<StandardSlider>;
|
||||
let sliderDebugElement: DebugElement;
|
||||
@@ -1134,11 +1183,12 @@ class SliderWithValueSmallerThanMin { }
|
||||
class SliderWithValueGreaterThanMax { }
|
||||
|
||||
@Component({
|
||||
template: `<md-slider (change)="onChange($event)"></md-slider>`,
|
||||
template: `<md-slider (change)="onChange($event)" (input)="onInput($event)"></md-slider>`,
|
||||
styles: [styles],
|
||||
})
|
||||
class SliderWithChangeHandler {
|
||||
onChange() { }
|
||||
onChange() { };
|
||||
onInput() { };
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -117,8 +117,9 @@ export class MdSlider implements ControlValueAccessor {
|
||||
|
||||
private _controlValueAccessorChangeFn: (value: any) => void = () => {};
|
||||
|
||||
/** The last value for which a change event was emitted. */
|
||||
private _lastEmittedValue: number = null;
|
||||
/** The last values for which a change or input event was emitted. */
|
||||
private _lastChangeValue: number = null;
|
||||
private _lastInputValue: number = null;
|
||||
|
||||
/** onTouch function registered via registerOnTouch (ControlValueAccessor). */
|
||||
onTouched: () => any = () => {};
|
||||
@@ -301,6 +302,9 @@ export class MdSlider implements ControlValueAccessor {
|
||||
/** Event emitted when the slider value has changed. */
|
||||
@Output() change = new EventEmitter<MdSliderChange>();
|
||||
|
||||
/** Event emitted when the slider thumb moves. */
|
||||
@Output() input = new EventEmitter<MdSliderChange>();
|
||||
|
||||
constructor(@Optional() private _dir: Dir, elementRef: ElementRef) {
|
||||
this._renderer = new SliderRenderer(elementRef);
|
||||
}
|
||||
@@ -325,6 +329,9 @@ export class MdSlider implements ControlValueAccessor {
|
||||
this._isSliding = false;
|
||||
this._renderer.addFocus();
|
||||
this._updateValueFromPosition({x: event.clientX, y: event.clientY});
|
||||
|
||||
/* Emits a change and input event if the value changed. */
|
||||
this._emitInputEvent();
|
||||
this._emitValueIfChanged();
|
||||
}
|
||||
|
||||
@@ -336,6 +343,9 @@ export class MdSlider implements ControlValueAccessor {
|
||||
// Prevent the slide from selecting anything else.
|
||||
event.preventDefault();
|
||||
this._updateValueFromPosition({x: event.center.x, y: event.center.y});
|
||||
|
||||
// Native range elements always emit `input` events when the value changed while sliding.
|
||||
this._emitInputEvent();
|
||||
}
|
||||
|
||||
_onSlideStart(event: HammerInput) {
|
||||
@@ -439,16 +449,23 @@ export class MdSlider implements ControlValueAccessor {
|
||||
|
||||
/** Emits a change event if the current value is different from the last emitted value. */
|
||||
private _emitValueIfChanged() {
|
||||
if (this.value != this._lastEmittedValue) {
|
||||
let event = new MdSliderChange();
|
||||
event.source = this;
|
||||
event.value = this.value;
|
||||
this._lastEmittedValue = this.value;
|
||||
if (this.value != this._lastChangeValue) {
|
||||
let event = this._createChangeEvent();
|
||||
this._lastChangeValue = this.value;
|
||||
this._controlValueAccessorChangeFn(this.value);
|
||||
this.change.emit(event);
|
||||
}
|
||||
}
|
||||
|
||||
/** Emits an input event when the current value is different from the last emitted value. */
|
||||
private _emitInputEvent() {
|
||||
if (this.value != this._lastInputValue) {
|
||||
let event = this._createChangeEvent();
|
||||
this._lastInputValue = this.value;
|
||||
this.input.emit(event);
|
||||
}
|
||||
}
|
||||
|
||||
/** Updates the amount of space between ticks as a percentage of the width of the slider. */
|
||||
private _updateTickIntervalPercent() {
|
||||
if (!this.tickInterval) {
|
||||
@@ -466,6 +483,16 @@ export class MdSlider implements ControlValueAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates a slider change object from the specified value. */
|
||||
private _createChangeEvent(value = this.value): MdSliderChange {
|
||||
let event = new MdSliderChange();
|
||||
|
||||
event.source = this;
|
||||
event.value = value;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/** Calculates the percentage of the slider that a value is. */
|
||||
private _calculatePercentage(value: number) {
|
||||
return (value - this.min) / (this.max - this.min);
|
||||
|
||||
Reference in New Issue
Block a user