Skip to content

Commit e5ae337

Browse files
authored
refactor(material-experimental/mdc-slide-toggle): remove usage of MDC adapter (#24935)
Bases the MDC slide toggle on top of the non-MDC one, instead of the MDC adapter.
1 parent 2ced52a commit e5ae337

File tree

6 files changed

+191
-296
lines changed

6 files changed

+191
-296
lines changed

src/material-experimental/mdc-slide-toggle/slide-toggle.html

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
type="button"
77
[class.mdc-switch--selected]="checked"
88
[class.mdc-switch--unselected]="!checked"
9+
[class.mdc-switch--checked]="checked"
10+
[class.mdc-switch--disabled]="disabled"
911
[tabIndex]="tabIndex"
1012
[disabled]="disabled"
1113
[attr.id]="buttonId"
@@ -14,7 +16,8 @@
1416
[attr.aria-labelledby]="_getAriaLabelledBy()"
1517
[attr.aria-describedby]="ariaDescribedby"
1618
[attr.aria-required]="required || null"
17-
(click)="_handleClick($event)"
19+
[attr.aria-checked]="checked"
20+
(click)="_handleClick()"
1821
#switch>
1922
<div class="mdc-switch__track"></div>
2023
<div class="mdc-switch__handle-track">

src/material-experimental/mdc-slide-toggle/slide-toggle.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ describe('MDC-based MatSlideToggle without forms', () => {
220220

221221
// We fall back to pointing to the label if a value isn't provided.
222222
expect(buttonElement.getAttribute('aria-labelledby')).toMatch(
223-
/mat-mdc-slide-toggle-label-\d+/,
223+
/mat-mdc-slide-toggle-\d+-label/,
224224
);
225225
}));
226226

src/material-experimental/mdc-slide-toggle/slide-toggle.ts

+23-193
Original file line numberDiff line numberDiff line change
@@ -10,40 +10,25 @@ import {
1010
ChangeDetectionStrategy,
1111
Component,
1212
ViewEncapsulation,
13-
AfterViewInit,
14-
OnDestroy,
1513
forwardRef,
1614
ViewChild,
1715
ElementRef,
18-
Input,
19-
Output,
20-
EventEmitter,
2116
ChangeDetectorRef,
2217
Attribute,
2318
Inject,
2419
Optional,
2520
} from '@angular/core';
26-
import {deprecated} from '@material/switch';
27-
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
28-
import {
29-
BooleanInput,
30-
coerceBooleanProperty,
31-
coerceNumberProperty,
32-
NumberInput,
33-
} from '@angular/cdk/coercion';
21+
import {NG_VALUE_ACCESSOR} from '@angular/forms';
3422
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
35-
import {ThemePalette} from '@angular/material-experimental/mdc-core';
3623
import {FocusMonitor} from '@angular/cdk/a11y';
24+
import {_MatSlideToggleBase} from '@angular/material/slide-toggle';
3725
import {
3826
MAT_SLIDE_TOGGLE_DEFAULT_OPTIONS,
3927
MatSlideToggleDefaultOptions,
4028
} from './slide-toggle-config';
4129

42-
// Increasing integer for generating unique ids for slide-toggle components.
43-
let nextUniqueId = 0;
44-
4530
/** @docs-private */
46-
export const MAT_SLIDE_TOGGLE_VALUE_ACCESSOR: any = {
31+
export const MAT_SLIDE_TOGGLE_VALUE_ACCESSOR = {
4732
provide: NG_VALUE_ACCESSOR,
4833
useExisting: forwardRef(() => MatSlideToggle),
4934
multi: true,
@@ -63,6 +48,7 @@ export class MatSlideToggleChange {
6348
selector: 'mat-slide-toggle',
6449
templateUrl: 'slide-toggle.html',
6550
styleUrls: ['slide-toggle.css'],
51+
inputs: ['disabled', 'disableRipple', 'color', 'tabIndex'],
6652
host: {
6753
'class': 'mat-mdc-slide-toggle',
6854
'[id]': 'id',
@@ -71,9 +57,6 @@ export class MatSlideToggleChange {
7157
'[attr.aria-label]': 'null',
7258
'[attr.name]': 'null',
7359
'[attr.aria-labelledby]': 'null',
74-
'[class.mat-primary]': 'color === "primary"',
75-
'[class.mat-accent]': 'color !== "primary" && color !== "warn"',
76-
'[class.mat-warn]': 'color === "warn"',
7760
'[class.mat-mdc-slide-toggle-focused]': '_focused',
7861
'[class.mat-mdc-slide-toggle-checked]': 'checked',
7962
'[class._mat-animation-noopable]': '_noopAnimations',
@@ -83,116 +66,9 @@ export class MatSlideToggleChange {
8366
changeDetection: ChangeDetectionStrategy.OnPush,
8467
providers: [MAT_SLIDE_TOGGLE_VALUE_ACCESSOR],
8568
})
86-
export class MatSlideToggle implements ControlValueAccessor, AfterViewInit, OnDestroy {
87-
private _onChange = (_: any) => {};
88-
private _onTouched = () => {};
89-
90-
private _uniqueId: string = `mat-mdc-slide-toggle-${++nextUniqueId}`;
91-
private _required: boolean = false;
92-
private _checked: boolean = false;
93-
private _foundation: deprecated.MDCSwitchFoundation;
94-
private _adapter: deprecated.MDCSwitchAdapter = {
95-
addClass: className => this._switchElement.nativeElement.classList.add(className),
96-
removeClass: className => this._switchElement.nativeElement.classList.remove(className),
97-
setNativeControlChecked: checked => (this._checked = checked),
98-
setNativeControlDisabled: disabled => (this._disabled = disabled),
99-
setNativeControlAttr: (name, value) => {
100-
this._switchElement.nativeElement.setAttribute(name, value);
101-
},
102-
};
103-
104-
/** Whether the slide toggle is currently focused. */
105-
_focused: boolean;
106-
107-
/** Whether noop animations are enabled. */
108-
_noopAnimations: boolean;
109-
69+
export class MatSlideToggle extends _MatSlideToggleBase<MatSlideToggleChange> {
11070
/** Unique ID for the label element. */
111-
_labelId = `mat-mdc-slide-toggle-label-${++nextUniqueId}`;
112-
113-
/** The color palette for this slide toggle. */
114-
@Input() color: ThemePalette;
115-
116-
/** Name value will be applied to the button element if present. */
117-
@Input() name: string | null = null;
118-
119-
/** A unique id for the slide-toggle button. If none is supplied, it will be auto-generated. */
120-
@Input() id: string = this._uniqueId;
121-
122-
/** Tabindex for the input element. */
123-
@Input()
124-
get tabIndex(): number {
125-
return this._tabIndex;
126-
}
127-
set tabIndex(value: NumberInput) {
128-
this._tabIndex = coerceNumberProperty(value);
129-
}
130-
private _tabIndex: number;
131-
132-
/** Whether the label should appear after or before the slide-toggle. Defaults to 'after'. */
133-
@Input() labelPosition: 'before' | 'after' = 'after';
134-
135-
/** Used to set the aria-label attribute on the underlying button element. */
136-
@Input('aria-label') ariaLabel: string | null = null;
137-
138-
/** Used to set the aria-labelledby attribute on the underlying button element. */
139-
@Input('aria-labelledby') ariaLabelledby: string | null = null;
140-
141-
/** Used to set the aria-describedby attribute on the underlying button element. */
142-
@Input('aria-describedby') ariaDescribedby: string;
143-
144-
/** Whether the slide-toggle is required. */
145-
@Input()
146-
get required(): boolean {
147-
return this._required;
148-
}
149-
set required(value: BooleanInput) {
150-
this._required = coerceBooleanProperty(value);
151-
}
152-
153-
/** Whether the slide-toggle element is checked or not. */
154-
@Input()
155-
get checked(): boolean {
156-
return this._checked;
157-
}
158-
set checked(value: BooleanInput) {
159-
this._checked = coerceBooleanProperty(value);
160-
161-
if (this._foundation) {
162-
this._foundation.setChecked(this._checked);
163-
}
164-
}
165-
166-
/** Whether to disable the ripple on this checkbox. */
167-
@Input()
168-
get disableRipple(): boolean {
169-
return this._disableRipple;
170-
}
171-
set disableRipple(disableRipple: BooleanInput) {
172-
this._disableRipple = coerceBooleanProperty(disableRipple);
173-
}
174-
private _disableRipple = false;
175-
176-
/** Whether the slide toggle is disabled. */
177-
@Input()
178-
get disabled(): boolean {
179-
return this._disabled;
180-
}
181-
set disabled(disabled: BooleanInput) {
182-
this._disabled = coerceBooleanProperty(disabled);
183-
184-
if (this._foundation) {
185-
this._foundation.setDisabled(this._disabled);
186-
}
187-
}
188-
private _disabled = false;
189-
190-
/** An event will be dispatched each time the slide-toggle changes its value. */
191-
@Output() readonly change: EventEmitter<MatSlideToggleChange> =
192-
new EventEmitter<MatSlideToggleChange>();
193-
194-
/** Event will be dispatched each time the slide-toggle input is toggled. */
195-
@Output() readonly toggleChange: EventEmitter<void> = new EventEmitter<void>();
71+
_labelId: string;
19672

19773
/** Returns the unique id for the visual hidden button. */
19874
get buttonId(): string {
@@ -203,51 +79,29 @@ export class MatSlideToggle implements ControlValueAccessor, AfterViewInit, OnDe
20379
@ViewChild('switch') _switchElement: ElementRef<HTMLElement>;
20480

20581
constructor(
206-
private _elementRef: ElementRef,
207-
private _focusMonitor: FocusMonitor,
208-
private _changeDetectorRef: ChangeDetectorRef,
82+
elementRef: ElementRef,
83+
focusMonitor: FocusMonitor,
84+
changeDetectorRef: ChangeDetectorRef,
20985
@Attribute('tabindex') tabIndex: string,
21086
@Inject(MAT_SLIDE_TOGGLE_DEFAULT_OPTIONS)
211-
public defaults: MatSlideToggleDefaultOptions,
87+
defaults: MatSlideToggleDefaultOptions,
21288
@Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string,
21389
) {
214-
this.tabIndex = parseInt(tabIndex) || 0;
215-
this.color = defaults.color || 'accent';
216-
this._noopAnimations = animationMode === 'NoopAnimations';
217-
}
218-
219-
ngAfterViewInit() {
220-
const foundation = (this._foundation = new deprecated.MDCSwitchFoundation(this._adapter));
221-
foundation.setDisabled(this.disabled);
222-
foundation.setChecked(this.checked);
223-
224-
this._focusMonitor.monitor(this._elementRef, true).subscribe(focusOrigin => {
225-
if (focusOrigin === 'keyboard' || focusOrigin === 'program') {
226-
this._focused = true;
227-
} else if (!focusOrigin) {
228-
// When a focused element becomes disabled, the browser *immediately* fires a blur event.
229-
// Angular does not expect events to be raised during change detection, so any state
230-
// change (such as a form control's ng-touched) will cause a changed-after-checked error.
231-
// See https://github.com/angular/angular/issues/17793. To work around this, we defer
232-
// telling the form control it has been touched until the next tick.
233-
Promise.resolve().then(() => {
234-
this._focused = false;
235-
this._onTouched();
236-
this._changeDetectorRef.markForCheck();
237-
});
238-
}
239-
});
240-
}
241-
242-
ngOnDestroy() {
243-
this._focusMonitor.stopMonitoring(this._elementRef);
244-
this._foundation?.destroy();
90+
super(
91+
elementRef,
92+
focusMonitor,
93+
changeDetectorRef,
94+
tabIndex,
95+
defaults,
96+
animationMode,
97+
'mat-mdc-slide-toggle-',
98+
);
99+
this._labelId = this._uniqueId + '-label';
245100
}
246101

247102
/** Method being called whenever the underlying button is clicked. */
248-
_handleClick(event: Event) {
103+
_handleClick() {
249104
this.toggleChange.emit();
250-
this._foundation.handleChange(event);
251105

252106
if (!this.defaults.disableToggleValue) {
253107
this.checked = !this.checked;
@@ -256,37 +110,13 @@ export class MatSlideToggle implements ControlValueAccessor, AfterViewInit, OnDe
256110
}
257111
}
258112

259-
/** Implemented as part of ControlValueAccessor. */
260-
writeValue(value: any): void {
261-
this.checked = !!value;
262-
this._changeDetectorRef.markForCheck();
263-
}
264-
265-
/** Implemented as part of ControlValueAccessor. */
266-
registerOnChange(fn: any): void {
267-
this._onChange = fn;
268-
}
269-
270-
/** Implemented as part of ControlValueAccessor. */
271-
registerOnTouched(fn: any): void {
272-
this._onTouched = fn;
273-
}
274-
275-
/** Implemented as a part of ControlValueAccessor. */
276-
setDisabledState(isDisabled: boolean): void {
277-
this.disabled = isDisabled;
278-
this._changeDetectorRef.markForCheck();
279-
}
280-
281113
/** Focuses the slide-toggle. */
282114
focus(): void {
283115
this._switchElement.nativeElement.focus();
284116
}
285117

286-
/** Toggles the checked state of the slide-toggle. */
287-
toggle(): void {
288-
this.checked = !this.checked;
289-
this._onChange(this.checked);
118+
protected _createChangeEvent(isChecked: boolean) {
119+
return new MatSlideToggleChange(this, isChecked);
290120
}
291121

292122
_getAriaLabelledBy() {

src/material/slide-toggle/slide-toggle.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<label [attr.for]="inputId" class="mat-slide-toggle-label" #label>
2-
<span #toggleBar class="mat-slide-toggle-bar"
2+
<span class="mat-slide-toggle-bar"
33
[class.mat-slide-toggle-bar-no-side-margin]="!labelContent.textContent || !labelContent.textContent.trim()">
44

55
<input #input class="mat-slide-toggle-input cdk-visually-hidden" type="checkbox"
@@ -17,7 +17,7 @@
1717
(change)="_onChangeEvent($event)"
1818
(click)="_onInputClick($event)">
1919

20-
<span class="mat-slide-toggle-thumb-container" #thumbContainer>
20+
<span class="mat-slide-toggle-thumb-container">
2121
<span class="mat-slide-toggle-thumb"></span>
2222
<span class="mat-slide-toggle-ripple mat-focus-indicator" mat-ripple
2323
[matRippleTrigger]="label"

0 commit comments

Comments
 (0)