Skip to content

Commit 10b9f24

Browse files
committed
perf(slider): convert slider adapters to class objects
Converts slider adapter to class object to hopefully reduce memory usage. Adds several methods to work around private fields and methods.
1 parent 544e335 commit 10b9f24

File tree

1 file changed

+115
-86
lines changed
  • src/material-experimental/mdc-slider

1 file changed

+115
-86
lines changed

src/material-experimental/mdc-slider/slider.ts

Lines changed: 115 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,101 @@ export const MAT_SLIDER_VALUE_ACCESSOR: any = {
7070
multi: true
7171
};
7272

73+
class SliderAdapter implements MDCSliderAdapter {
74+
constructor(private _delegate: MatSlider) {}
75+
76+
hasClass = (className: string) =>
77+
this._delegate.getElementRef().nativeElement.classList.contains(className);
78+
addClass = (className: string) =>
79+
this._delegate.getElementRef().nativeElement.classList.add(className);
80+
removeClass = (className: string) =>
81+
this._delegate.getElementRef().nativeElement.classList.remove(className);
82+
getAttribute = (name: string) => this._delegate.getElementRef().nativeElement.getAttribute(name);
83+
setAttribute = (name: string, value: string) =>
84+
this._delegate.getElementRef().nativeElement.setAttribute(name, value);
85+
removeAttribute = (name: string) =>
86+
this._delegate.getElementRef().nativeElement.removeAttribute(name);
87+
computeBoundingRect = () => this._delegate.getElementRef().nativeElement.getBoundingClientRect();
88+
getTabIndex = () => this._delegate.getElementRef().nativeElement.tabIndex;
89+
registerInteractionHandler = (evtType: any, handler: (this: HTMLElement, ev: any) => any) =>
90+
// Interaction event handlers (which handle keyboard interaction) cannot be passive
91+
// as they will prevent the default behavior. Additionally we can't run these event
92+
// handlers outside of the Angular zone because we rely on the events to cause the
93+
// component tree to be re-checked.
94+
// TODO: take in the event listener options from the adapter once MDC supports it.
95+
this._delegate.getElementRef().nativeElement.addEventListener(
96+
evtType, handler, activeListenerOptions)
97+
deregisterInteractionHandler = (evtType: any, handler: (this: HTMLElement, ev: any) => any) =>
98+
this._delegate.getElementRef().nativeElement.removeEventListener(evtType, handler)
99+
registerThumbContainerInteractionHandler =
100+
(evtType: any, handler: (this: HTMLElement, ev: any) => any) => {
101+
// The thumb container interaction handlers are currently just used for transition
102+
// events which don't need to run in the Angular zone.
103+
this._delegate.getNgZone().runOutsideAngular(() => {
104+
this._delegate._thumbContainer.nativeElement
105+
.addEventListener(evtType, handler, passiveListenerOptions);
106+
});
107+
}
108+
deregisterThumbContainerInteractionHandler =
109+
(evtType: any, handler: (this: HTMLElement, ev: any) => any) => {
110+
this._delegate._thumbContainer.nativeElement
111+
.removeEventListener(evtType, handler, passiveListenerOptions);
112+
}
113+
registerBodyInteractionHandler = (evtType: any, handler: (this: HTMLElement, ev: any) => any) =>
114+
// Body event handlers (which handle thumb sliding) cannot be passive as they will
115+
// prevent the default behavior. Additionally we can't run these event handlers
116+
// outside of the Angular zone because we rely on the events to cause the component
117+
// tree to be re-checked.
118+
document.body.addEventListener(evtType, handler);
119+
deregisterBodyInteractionHandler = (evtType: any, handler: (this: HTMLElement, ev: any) => any) =>
120+
document.body.removeEventListener(evtType, handler);
121+
registerResizeHandler = (handler: (this: Window, ev: UIEvent) => any) => {
122+
// The resize handler is currently responsible for detecting slider dimension
123+
// changes and therefore doesn't cause a value change that needs to be propagated.
124+
this._delegate.getNgZone().runOutsideAngular(() => window.addEventListener('resize', handler));
125+
}
126+
deregisterResizeHandler =
127+
(handler: (this: Window, ev: UIEvent) => any) => window.removeEventListener('resize', handler)
128+
notifyInput =
129+
() => {
130+
const newValue = this._delegate.getFoundation().getValue();
131+
// MDC currently fires the input event multiple times.
132+
// TODO(devversion): remove this check once the input notifications are fixed.
133+
if (newValue !== this._delegate.value) {
134+
this._delegate.value = newValue;
135+
this._delegate.input.emit(this._delegate._createChangeEvent(newValue));
136+
}
137+
};
138+
notifyChange =
139+
() => {
140+
// TODO(devversion): bug in MDC where only the "change" event is emitted if a keypress
141+
// updated the value. Material and native range sliders also emit an input event.
142+
// Usually we sync the "value" in the "input" event, but as a workaround we now sync
143+
// the value in the "change" event.
144+
this._delegate.value = this._delegate.getFoundation().getValue();
145+
this._delegate._emitChangeEvent(this._delegate.value!);
146+
};
147+
setThumbContainerStyleProperty =
148+
(propertyName: string, value: string | null) => {
149+
this._delegate._thumbContainer.nativeElement.style.setProperty(propertyName, value);
150+
}
151+
setTrackStyleProperty =
152+
(propertyName: string, value: string | null) => {
153+
this._delegate._track.nativeElement.style.setProperty(propertyName, value);
154+
}
155+
setMarkerValue =
156+
() => {
157+
// Mark the component for check as the thumb label needs to be re-rendered.
158+
this._delegate.getChangeDetectorRef().markForCheck();
159+
}
160+
setTrackMarkers =
161+
(step: number, max: number, min: number) => {
162+
this._delegate._trackMarker.nativeElement.style.setProperty(
163+
'background', this._delegate._getTrackMarkersBackground(min, max, step));
164+
}
165+
isRTL = () => this._delegate._isRtl()
166+
}
167+
73168
/** A simple change event emitted by the MatSlider component. */
74169
export class MatSliderChange {
75170
/** The MatSlider that changed. */
@@ -221,89 +316,7 @@ export class MatSlider implements AfterViewInit, OnChanges, OnDestroy, ControlVa
221316
private _disabled = false;
222317

223318
/** Adapter for the MDC slider foundation. */
224-
private _sliderAdapter: MDCSliderAdapter = {
225-
hasClass: (className) => this._elementRef.nativeElement.classList.contains(className),
226-
addClass: (className) => this._elementRef.nativeElement.classList.add(className),
227-
removeClass: (className) => this._elementRef.nativeElement.classList.remove(className),
228-
getAttribute: (name) => this._elementRef.nativeElement.getAttribute(name),
229-
setAttribute: (name, value) => this._elementRef.nativeElement.setAttribute(name, value),
230-
removeAttribute: (name) => this._elementRef.nativeElement.removeAttribute(name),
231-
computeBoundingRect: () => this._elementRef.nativeElement.getBoundingClientRect(),
232-
getTabIndex: () => this._elementRef.nativeElement.tabIndex,
233-
registerInteractionHandler: (evtType, handler) =>
234-
// Interaction event handlers (which handle keyboard interaction) cannot be passive
235-
// as they will prevent the default behavior. Additionally we can't run these event
236-
// handlers outside of the Angular zone because we rely on the events to cause the
237-
// component tree to be re-checked.
238-
// TODO: take in the event listener options from the adapter once MDC supports it.
239-
this._elementRef.nativeElement.addEventListener(evtType, handler, activeListenerOptions),
240-
deregisterInteractionHandler: (evtType, handler) =>
241-
this._elementRef.nativeElement.removeEventListener(evtType, handler),
242-
registerThumbContainerInteractionHandler: (evtType, handler) => {
243-
// The thumb container interaction handlers are currently just used for transition
244-
// events which don't need to run in the Angular zone.
245-
this._ngZone.runOutsideAngular(() => {
246-
this._thumbContainer.nativeElement
247-
.addEventListener(evtType, handler, passiveListenerOptions);
248-
});
249-
},
250-
deregisterThumbContainerInteractionHandler: (evtType, handler) => {
251-
this._thumbContainer.nativeElement
252-
.removeEventListener(evtType, handler, passiveListenerOptions);
253-
},
254-
registerBodyInteractionHandler: (evtType, handler) =>
255-
// Body event handlers (which handle thumb sliding) cannot be passive as they will
256-
// prevent the default behavior. Additionally we can't run these event handlers
257-
// outside of the Angular zone because we rely on the events to cause the component
258-
// tree to be re-checked.
259-
document.body.addEventListener(evtType, handler),
260-
deregisterBodyInteractionHandler: (evtType, handler) =>
261-
document.body.removeEventListener(evtType, handler),
262-
registerResizeHandler: (handler) => {
263-
// The resize handler is currently responsible for detecting slider dimension
264-
// changes and therefore doesn't cause a value change that needs to be propagated.
265-
this._ngZone.runOutsideAngular(() => window.addEventListener('resize', handler));
266-
},
267-
deregisterResizeHandler: (handler) => window.removeEventListener('resize', handler),
268-
notifyInput:
269-
() => {
270-
const newValue = this._foundation.getValue();
271-
// MDC currently fires the input event multiple times.
272-
// TODO(devversion): remove this check once the input notifications are fixed.
273-
if (newValue !== this.value) {
274-
this.value = newValue;
275-
this.input.emit(this._createChangeEvent(newValue));
276-
}
277-
},
278-
notifyChange:
279-
() => {
280-
// TODO(devversion): bug in MDC where only the "change" event is emitted if a keypress
281-
// updated the value. Material and native range sliders also emit an input event.
282-
// Usually we sync the "value" in the "input" event, but as a workaround we now sync
283-
// the value in the "change" event.
284-
this.value = this._foundation.getValue();
285-
this._emitChangeEvent(this.value!);
286-
},
287-
setThumbContainerStyleProperty:
288-
(propertyName, value) => {
289-
this._thumbContainer.nativeElement.style.setProperty(propertyName, value);
290-
},
291-
setTrackStyleProperty:
292-
(propertyName, value) => {
293-
this._track.nativeElement.style.setProperty(propertyName, value);
294-
},
295-
setMarkerValue:
296-
() => {
297-
// Mark the component for check as the thumb label needs to be re-rendered.
298-
this._changeDetectorRef.markForCheck();
299-
},
300-
setTrackMarkers:
301-
(step, max, min) => {
302-
this._trackMarker.nativeElement.style.setProperty(
303-
'background', this._getTrackMarkersBackground(min, max, step));
304-
},
305-
isRTL: () => this._isRtl(),
306-
};
319+
private _sliderAdapter: MDCSliderAdapter = new SliderAdapter(this);
307320

308321
/** Instance of the MDC slider foundation for this slider. */
309322
private _foundation = new MDCSliderFoundation(this._sliderAdapter);
@@ -411,6 +424,22 @@ export class MatSlider implements AfterViewInit, OnChanges, OnDestroy, ControlVa
411424
}
412425
}
413426

427+
getChangeDetectorRef() {
428+
return this._changeDetectorRef;
429+
}
430+
431+
getElementRef() {
432+
return this._elementRef;
433+
}
434+
435+
getFoundation() {
436+
return this._foundation;
437+
}
438+
439+
getNgZone() {
440+
return this._ngZone;
441+
}
442+
414443
/** Focuses the slider. */
415444
focus(options?: FocusOptions) {
416445
this._elementRef.nativeElement.focus(options);
@@ -430,22 +459,22 @@ export class MatSlider implements AfterViewInit, OnChanges, OnDestroy, ControlVa
430459
}
431460

432461
/** Creates a slider change object from the specified value. */
433-
private _createChangeEvent(newValue: number): MatSliderChange {
462+
_createChangeEvent(newValue: number): MatSliderChange {
434463
const event = new MatSliderChange();
435464
event.source = this;
436465
event.value = newValue;
437466
return event;
438467
}
439468

440469
/** Emits a change event and notifies the control value accessor. */
441-
private _emitChangeEvent(newValue: number) {
470+
_emitChangeEvent(newValue: number) {
442471
this._controlValueAccessorChangeFn(newValue);
443472
this.valueChange.emit(newValue);
444473
this.change.emit(this._createChangeEvent(newValue));
445474
}
446475

447476
/** Computes the CSS background value for the track markers (aka ticks). */
448-
private _getTrackMarkersBackground(min: number, max: number, step: number) {
477+
_getTrackMarkersBackground(min: number, max: number, step: number) {
449478
if (!this.tickInterval) {
450479
return '';
451480
}

0 commit comments

Comments
 (0)