Skip to content

Commit be22e81

Browse files
crisbetoandrewseguin
authored andcommitted
refactor(slide-toggle): remove SlideToggleRenderer (#10945)
Removes the `SlideToggleRenderer` class and moves all of its logic into the `MatSlideToggle`. After the switch to Domino, it no longer makes sense to keep all of the DOM manipulation separately. Furthermore, this will output less ES5 code and makes everything easier to follow.
1 parent a609acf commit be22e81

File tree

2 files changed

+62
-93
lines changed

2 files changed

+62
-93
lines changed

src/lib/slide-toggle/slide-toggle.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<label class="mat-slide-toggle-label" #label>
22

3-
<div class="mat-slide-toggle-bar"
3+
<div #toggleBar class="mat-slide-toggle-bar"
44
[class.mat-slide-toggle-bar-no-side-margin]="!labelContent.textContent || !labelContent.textContent.trim()">
55

66
<input #input class="mat-slide-toggle-input cdk-visually-hidden" type="checkbox"
@@ -16,6 +16,7 @@
1616
(click)="_onInputClick($event)">
1717

1818
<div class="mat-slide-toggle-thumb-container"
19+
#thumbContainer
1920
(slidestart)="_onDragStart()"
2021
(slide)="_onDrag($event)"
2122
(slideend)="_onDragEnd()">

src/lib/slide-toggle/slide-toggle.ts

Lines changed: 60 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,30 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
9292
private onTouched = () => {};
9393

9494
private _uniqueId: string = `mat-slide-toggle-${++nextUniqueId}`;
95-
private _slideRenderer: SlideToggleRenderer;
9695
private _required: boolean = false;
9796
private _checked: boolean = false;
9897

9998
/** Reference to the focus state ripple. */
10099
private _focusRipple: RippleRef | null;
101100

101+
/** Whether the thumb is currently being dragged. */
102+
private _dragging = false;
103+
104+
/** Previous checked state before drag started. */
105+
private _previousChecked: boolean;
106+
107+
/** Width of the thumb bar of the slide-toggle. */
108+
private _thumbBarWidth: number;
109+
110+
/** Percentage of the thumb while dragging. Percentage as fraction of 100. */
111+
private _dragPercentage: number;
112+
113+
/** Reference to the thumb HTMLElement. */
114+
@ViewChild('thumbContainer') _thumbEl: ElementRef<HTMLElement>;
115+
116+
/** Reference to the thumb bar HTMLElement. */
117+
@ViewChild('toggleBar') _thumbBarEl: ElementRef<HTMLElement>;
118+
102119
/** Name value will be applied to the input element if present */
103120
@Input() name: string | null = null;
104121

@@ -142,7 +159,11 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
142159
@ViewChild(MatRipple) _ripple: MatRipple;
143160

144161
constructor(elementRef: ElementRef,
145-
private _platform: Platform,
162+
/**
163+
* @deprecated The `_platform` parameter to be removed.
164+
* @deletion-target 7.0.0
165+
*/
166+
_platform: Platform,
146167
private _focusMonitor: FocusMonitor,
147168
private _changeDetectorRef: ChangeDetectorRef,
148169
@Attribute('tabindex') tabIndex: string,
@@ -153,8 +174,6 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
153174
}
154175

155176
ngAfterContentInit() {
156-
this._slideRenderer = new SlideToggleRenderer(this._elementRef, this._platform);
157-
158177
this._focusMonitor
159178
.monitor(this._inputElement.nativeElement)
160179
.subscribe(focusOrigin => this._onInputFocusChange(focusOrigin));
@@ -174,7 +193,7 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
174193
// Releasing the pointer over the `<label>` element while dragging triggers another
175194
// click event on the `<label>` element. This means that the checked state of the underlying
176195
// input changed unintentionally and needs to be changed back.
177-
if (this._slideRenderer.dragging) {
196+
if (this._dragging) {
178197
this._inputElement.nativeElement.checked = this.checked;
179198
return;
180199
}
@@ -255,21 +274,41 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
255274
this.change.emit(new MatSlideToggleChange(this, this.checked));
256275
}
257276

277+
/** Retrieves the percentage of thumb from the moved distance. Percentage as fraction of 100. */
278+
private _getDragPercentage(distance: number) {
279+
let percentage = (distance / this._thumbBarWidth) * 100;
280+
281+
// When the toggle was initially checked, then we have to start the drag at the end.
282+
if (this._previousChecked) {
283+
percentage += 100;
284+
}
285+
286+
return Math.max(0, Math.min(percentage, 100));
287+
}
288+
258289
_onDragStart() {
259-
if (!this.disabled) {
260-
this._slideRenderer.startThumbDrag(this.checked);
290+
if (!this.disabled && !this._dragging) {
291+
const thumbEl = this._thumbEl.nativeElement;
292+
this._thumbBarWidth = this._thumbBarEl.nativeElement.clientWidth - thumbEl.clientWidth;
293+
thumbEl.classList.add('mat-dragging');
294+
295+
this._previousChecked = this.checked;
296+
this._dragging = true;
261297
}
262298
}
263299

264300
_onDrag(event: HammerInput) {
265-
if (this._slideRenderer.dragging) {
266-
this._slideRenderer.updateThumbPosition(event.deltaX);
301+
if (this._dragging) {
302+
this._dragPercentage = this._getDragPercentage(event.deltaX);
303+
// Calculate the moved distance based on the thumb bar width.
304+
const dragX = (this._dragPercentage / 100) * this._thumbBarWidth;
305+
this._thumbEl.nativeElement.style.transform = `translate3d(${dragX}px, 0, 0)`;
267306
}
268307
}
269308

270309
_onDragEnd() {
271-
if (this._slideRenderer.dragging) {
272-
const newCheckedValue = this._slideRenderer.dragPercentage > 50;
310+
if (this._dragging) {
311+
const newCheckedValue = this._dragPercentage > 50;
273312

274313
if (newCheckedValue !== this.checked) {
275314
this.checked = newCheckedValue;
@@ -278,9 +317,16 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
278317

279318
// The drag should be stopped outside of the current event handler, otherwise the
280319
// click event will be fired before it and will revert the drag change.
281-
this._ngZone.runOutsideAngular(() => {
282-
setTimeout(() => this._slideRenderer.stopThumbDrag());
283-
});
320+
this._ngZone.runOutsideAngular(() => setTimeout(() => {
321+
if (this._dragging) {
322+
this._dragging = false;
323+
this._thumbEl.nativeElement.classList.remove('mat-dragging');
324+
325+
// Reset the transform because the component will take care
326+
// of the thumb position after drag.
327+
this._thumbEl.nativeElement.style.transform = '';
328+
}
329+
}));
284330
}
285331
}
286332

@@ -292,81 +338,3 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
292338
this._changeDetectorRef.markForCheck();
293339
}
294340
}
295-
296-
/**
297-
* Renderer for the Slide Toggle component, which separates DOM modification in its own class
298-
*/
299-
class SlideToggleRenderer {
300-
301-
/** Reference to the thumb HTMLElement. */
302-
private _thumbEl: HTMLElement;
303-
304-
/** Reference to the thumb bar HTMLElement. */
305-
private _thumbBarEl: HTMLElement;
306-
307-
/** Width of the thumb bar of the slide-toggle. */
308-
private _thumbBarWidth: number;
309-
310-
/** Previous checked state before drag started. */
311-
private _previousChecked: boolean;
312-
313-
/** Percentage of the thumb while dragging. Percentage as fraction of 100. */
314-
dragPercentage: number;
315-
316-
/** Whether the thumb is currently being dragged. */
317-
dragging: boolean = false;
318-
319-
constructor(elementRef: ElementRef, platform: Platform) {
320-
// We only need to interact with these elements when we're on the browser, so only grab
321-
// the reference in that case.
322-
if (platform.isBrowser) {
323-
this._thumbEl = elementRef.nativeElement.querySelector('.mat-slide-toggle-thumb-container');
324-
this._thumbBarEl = elementRef.nativeElement.querySelector('.mat-slide-toggle-bar');
325-
}
326-
}
327-
328-
/** Initializes the drag of the slide-toggle. */
329-
startThumbDrag(checked: boolean): void {
330-
if (this.dragging) { return; }
331-
332-
this._thumbBarWidth = this._thumbBarEl.clientWidth - this._thumbEl.clientWidth;
333-
this._thumbEl.classList.add('mat-dragging');
334-
335-
this._previousChecked = checked;
336-
this.dragging = true;
337-
}
338-
339-
/** Resets the current drag and returns the new checked value. */
340-
stopThumbDrag(): boolean {
341-
if (!this.dragging) { return false; }
342-
343-
this.dragging = false;
344-
this._thumbEl.classList.remove('mat-dragging');
345-
346-
// Reset the transform because the component will take care of the thumb position after drag.
347-
this._thumbEl.style.transform = '';
348-
349-
return this.dragPercentage > 50;
350-
}
351-
352-
/** Updates the thumb containers position from the specified distance. */
353-
updateThumbPosition(distance: number): void {
354-
this.dragPercentage = this._getDragPercentage(distance);
355-
// Calculate the moved distance based on the thumb bar width.
356-
const dragX = (this.dragPercentage / 100) * this._thumbBarWidth;
357-
this._thumbEl.style.transform = `translate3d(${dragX}px, 0, 0)`;
358-
}
359-
360-
/** Retrieves the percentage of thumb from the moved distance. Percentage as fraction of 100. */
361-
private _getDragPercentage(distance: number) {
362-
let percentage = (distance / this._thumbBarWidth) * 100;
363-
364-
// When the toggle was initially checked, then we have to start the drag at the end.
365-
if (this._previousChecked) {
366-
percentage += 100;
367-
}
368-
369-
return Math.max(0, Math.min(percentage, 100));
370-
}
371-
372-
}

0 commit comments

Comments
 (0)