1013 lines
35 KiB
TypeScript
1013 lines
35 KiB
TypeScript
|
|
import {FocusMonitor} from '@angular/cdk/a11y';
|
||
|
|
import {BidiModule, Direction} from '@angular/cdk/bidi';
|
||
|
|
import {dispatchFakeEvent} from '@angular/cdk/testing/private';
|
||
|
|
import {Component} from '@angular/core';
|
||
|
|
import {
|
||
|
|
ComponentFixture,
|
||
|
|
TestBed,
|
||
|
|
fakeAsync,
|
||
|
|
flush,
|
||
|
|
flushMicrotasks,
|
||
|
|
inject,
|
||
|
|
tick,
|
||
|
|
} from '@angular/core/testing';
|
||
|
|
import {FormControl, FormsModule, NgModel, ReactiveFormsModule} from '@angular/forms';
|
||
|
|
import {By} from '@angular/platform-browser';
|
||
|
|
import {MatSlideToggle, MatSlideToggleChange, MatSlideToggleModule} from './index';
|
||
|
|
import {MAT_SLIDE_TOGGLE_DEFAULT_OPTIONS} from './slide-toggle-config';
|
||
|
|
|
||
|
|
describe('MatSlideToggle without forms', () => {
|
||
|
|
beforeEach(() => {
|
||
|
|
TestBed.configureTestingModule({
|
||
|
|
imports: [
|
||
|
|
MatSlideToggleModule,
|
||
|
|
BidiModule,
|
||
|
|
SlideToggleBasic,
|
||
|
|
SlideToggleCheckedAndDisabledAttr,
|
||
|
|
SlideToggleWithTabindexAttr,
|
||
|
|
SlideToggleWithoutLabel,
|
||
|
|
SlideToggleProjectedLabel,
|
||
|
|
TextBindingComponent,
|
||
|
|
SlideToggleWithStaticAriaAttributes,
|
||
|
|
],
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('basic behavior', () => {
|
||
|
|
let fixture: ComponentFixture<any>;
|
||
|
|
|
||
|
|
let testComponent: SlideToggleBasic;
|
||
|
|
let slideToggle: MatSlideToggle;
|
||
|
|
let slideToggleElement: HTMLElement;
|
||
|
|
let labelElement: HTMLLabelElement;
|
||
|
|
let buttonElement: HTMLButtonElement;
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
fixture = TestBed.createComponent(SlideToggleBasic);
|
||
|
|
|
||
|
|
// Enable jasmine spies on event functions, which may trigger at initialization
|
||
|
|
// of the slide-toggle component.
|
||
|
|
spyOn(fixture.debugElement.componentInstance, 'onSlideChange').and.callThrough();
|
||
|
|
spyOn(fixture.debugElement.componentInstance, 'onSlideClick').and.callThrough();
|
||
|
|
|
||
|
|
// Initialize the slide-toggle component, by triggering the first change detection cycle.
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const slideToggleDebug = fixture.debugElement.query(By.css('mat-slide-toggle'))!;
|
||
|
|
|
||
|
|
testComponent = fixture.debugElement.componentInstance;
|
||
|
|
slideToggle = slideToggleDebug.componentInstance;
|
||
|
|
slideToggleElement = slideToggleDebug.nativeElement;
|
||
|
|
buttonElement = fixture.debugElement.query(By.css('button'))!.nativeElement;
|
||
|
|
labelElement = fixture.debugElement.query(By.css('label'))!.nativeElement;
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should apply class based on color attribute', () => {
|
||
|
|
testComponent.slideColor = 'primary';
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(slideToggleElement.classList).toContain('mat-primary');
|
||
|
|
|
||
|
|
testComponent.slideColor = 'accent';
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(slideToggleElement.classList).toContain('mat-accent');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should correctly update the disabled property', () => {
|
||
|
|
expect(buttonElement.disabled).toBeFalsy();
|
||
|
|
|
||
|
|
testComponent.isDisabled = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.disabled).toBeTruthy();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should correctly update the checked property', () => {
|
||
|
|
expect(slideToggle.checked).toBeFalsy();
|
||
|
|
expect(buttonElement.getAttribute('aria-checked')).toBe('false');
|
||
|
|
|
||
|
|
testComponent.slideChecked = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.getAttribute('aria-checked')).toBe('true');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should set the toggle to checked on click', fakeAsync(() => {
|
||
|
|
expect(slideToggle.checked).toBe(false);
|
||
|
|
expect(buttonElement.getAttribute('aria-checked')).toBe('false');
|
||
|
|
expect(slideToggleElement.classList).not.toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
|
||
|
|
labelElement.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
expect(slideToggleElement.classList).toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
expect(slideToggle.checked).toBe(true);
|
||
|
|
expect(buttonElement.getAttribute('aria-checked')).toBe('true');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should not trigger the click event multiple times', fakeAsync(() => {
|
||
|
|
// By default, when clicking on a label element, a generated click will be dispatched
|
||
|
|
// on the associated button element.
|
||
|
|
// Since we're using a label element and a visual hidden button, this behavior can led
|
||
|
|
// to an issue, where the click events on the slide-toggle are getting executed twice.
|
||
|
|
|
||
|
|
expect(slideToggle.checked).toBe(false);
|
||
|
|
expect(slideToggleElement.classList).not.toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
|
||
|
|
labelElement.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
tick();
|
||
|
|
|
||
|
|
expect(slideToggleElement.classList).toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
expect(slideToggle.checked).toBe(true);
|
||
|
|
expect(testComponent.onSlideClick).toHaveBeenCalledTimes(1);
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should trigger the change event properly', fakeAsync(() => {
|
||
|
|
expect(slideToggleElement.classList).not.toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
|
||
|
|
labelElement.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
expect(slideToggleElement.classList).toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
expect(testComponent.onSlideChange).toHaveBeenCalledTimes(1);
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should not trigger the change event by changing the native value', fakeAsync(() => {
|
||
|
|
expect(slideToggleElement.classList).not.toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
|
||
|
|
testComponent.slideChecked = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(slideToggleElement.classList).toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
tick();
|
||
|
|
|
||
|
|
expect(testComponent.onSlideChange).not.toHaveBeenCalled();
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should add a suffix to the element id', () => {
|
||
|
|
testComponent.slideId = 'myId';
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(slideToggleElement.id).toBe('myId');
|
||
|
|
expect(buttonElement.id).toBe(`${slideToggleElement.id}-button`);
|
||
|
|
|
||
|
|
testComponent.slideId = 'nextId';
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(slideToggleElement.id).toBe('nextId');
|
||
|
|
expect(buttonElement.id).toBe(`${slideToggleElement.id}-button`);
|
||
|
|
|
||
|
|
testComponent.slideId = null;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
// Once the id binding is set to null, the id property should auto-generate a unique id.
|
||
|
|
expect(buttonElement.id).toMatch(/mat-mdc-slide-toggle-\w+\d+-button/);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should forward the tabIndex to the underlying element', () => {
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.tabIndex).toBe(0);
|
||
|
|
|
||
|
|
testComponent.slideTabindex = 4;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.tabIndex).toBe(4);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should forward the specified name to the element', () => {
|
||
|
|
testComponent.slideName = 'myName';
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.name).toBe('myName');
|
||
|
|
|
||
|
|
testComponent.slideName = 'nextName';
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.name).toBe('nextName');
|
||
|
|
|
||
|
|
testComponent.slideName = null;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.name).toBe('');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should forward the aria-label attribute to the element', () => {
|
||
|
|
testComponent.slideLabel = 'ariaLabel';
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.getAttribute('aria-label')).toBe('ariaLabel');
|
||
|
|
|
||
|
|
testComponent.slideLabel = null;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.hasAttribute('aria-label')).toBeFalsy();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should forward the aria-labelledby attribute to the element', () => {
|
||
|
|
testComponent.slideLabelledBy = 'ariaLabelledBy';
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.getAttribute('aria-labelledby')).toBe('ariaLabelledBy');
|
||
|
|
|
||
|
|
testComponent.slideLabelledBy = null;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
// We fall back to pointing to the label if a value isn't provided.
|
||
|
|
expect(buttonElement.getAttribute('aria-labelledby')).toMatch(
|
||
|
|
/mat-mdc-slide-toggle-\w+\d+-label/,
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should forward the aria-describedby attribute to the element', () => {
|
||
|
|
testComponent.slideAriaDescribedBy = 'some-element';
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.getAttribute('aria-describedby')).toBe('some-element');
|
||
|
|
|
||
|
|
testComponent.slideAriaDescribedBy = null;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.hasAttribute('aria-describedby')).toBe(false);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should set the `for` attribute to the id of the element', () => {
|
||
|
|
expect(labelElement.getAttribute('for')).toBeTruthy();
|
||
|
|
expect(buttonElement.getAttribute('id')).toBeTruthy();
|
||
|
|
expect(labelElement.getAttribute('for')).toBe(buttonElement.getAttribute('id'));
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should emit the new values properly', fakeAsync(() => {
|
||
|
|
labelElement.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
tick();
|
||
|
|
|
||
|
|
// We're checking the arguments type / emitted value to be a boolean, because sometimes the
|
||
|
|
// emitted value can be a DOM Event, which is not valid.
|
||
|
|
// See angular/angular#4059
|
||
|
|
expect(testComponent.lastEvent.checked).toBe(true);
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should support subscription on the change observable', fakeAsync(() => {
|
||
|
|
const spy = jasmine.createSpy('change spy');
|
||
|
|
const subscription = slideToggle.change.subscribe(spy);
|
||
|
|
|
||
|
|
labelElement.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
tick();
|
||
|
|
|
||
|
|
expect(spy).toHaveBeenCalledWith(jasmine.objectContaining({checked: true}));
|
||
|
|
subscription.unsubscribe();
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should forward the required attribute', () => {
|
||
|
|
testComponent.isRequired = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.getAttribute('aria-required')).toBe('true');
|
||
|
|
|
||
|
|
testComponent.isRequired = false;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.getAttribute('aria-required')).toBe(null);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should focus on underlying element when focus() is called', fakeAsync(() => {
|
||
|
|
expect(document.activeElement).not.toBe(buttonElement);
|
||
|
|
|
||
|
|
slideToggle.focus();
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
expect(document.activeElement).toBe(buttonElement);
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should not manually move focus to underlying when focus comes from mouse or touch', fakeAsync(
|
||
|
|
inject([FocusMonitor], (focusMonitor: FocusMonitor) => {
|
||
|
|
expect(document.activeElement).not.toBe(buttonElement);
|
||
|
|
|
||
|
|
focusMonitor.focusVia(slideToggleElement, 'mouse');
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
expect(document.activeElement).not.toBe(buttonElement);
|
||
|
|
|
||
|
|
focusMonitor.focusVia(slideToggleElement, 'touch');
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
expect(document.activeElement).not.toBe(buttonElement);
|
||
|
|
}),
|
||
|
|
));
|
||
|
|
|
||
|
|
it('should set a element class if labelPosition is set to before', fakeAsync(() => {
|
||
|
|
const formField = slideToggleElement.querySelector('.mdc-form-field')!;
|
||
|
|
|
||
|
|
expect(formField.classList).not.toContain('mdc-form-field--align-end');
|
||
|
|
|
||
|
|
testComponent.labelPosition = 'before';
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(formField.classList).toContain('mdc-form-field--align-end');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should show ripples', fakeAsync(() => {
|
||
|
|
const rippleSelector = '.mat-ripple-element';
|
||
|
|
const switchElement = slideToggleElement.querySelector('.mdc-switch')!;
|
||
|
|
|
||
|
|
expect(slideToggleElement.querySelectorAll(rippleSelector).length).toBe(0);
|
||
|
|
|
||
|
|
dispatchFakeEvent(switchElement, 'mousedown');
|
||
|
|
dispatchFakeEvent(switchElement, 'mouseup');
|
||
|
|
|
||
|
|
expect(slideToggleElement.querySelectorAll(rippleSelector).length).toBe(1);
|
||
|
|
flush();
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should not show ripples when disableRipple is set', fakeAsync(() => {
|
||
|
|
const switchElement = slideToggleElement.querySelector('.mdc-switch')!;
|
||
|
|
const rippleSelector = '.mat-ripple-element';
|
||
|
|
testComponent.disableRipple = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(slideToggleElement.querySelectorAll(rippleSelector).length).toBe(0);
|
||
|
|
|
||
|
|
dispatchFakeEvent(switchElement, 'mousedown');
|
||
|
|
dispatchFakeEvent(switchElement, 'mouseup');
|
||
|
|
|
||
|
|
expect(slideToggleElement.querySelectorAll(rippleSelector).length).toBe(0);
|
||
|
|
flush();
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should have a focus indicator', fakeAsync(() => {
|
||
|
|
const rippleElement = slideToggleElement.querySelector('.mat-mdc-slide-toggle-ripple')!;
|
||
|
|
expect(rippleElement.classList).toContain('mat-focus-indicator');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should be able to hide the icon', fakeAsync(() => {
|
||
|
|
expect(slideToggleElement.querySelector('.mdc-switch__icons')).toBeTruthy();
|
||
|
|
|
||
|
|
testComponent.hideIcon = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(slideToggleElement.querySelector('.mdc-switch__icons')).toBeFalsy();
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should be able to mark a slide toggle as interactive while it is disabled', fakeAsync(() => {
|
||
|
|
testComponent.isDisabled = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.disabled).toBe(true);
|
||
|
|
expect(buttonElement.hasAttribute('aria-disabled')).toBe(false);
|
||
|
|
expect(buttonElement.getAttribute('tabindex')).toBe('-1');
|
||
|
|
expect(buttonElement.classList).not.toContain('mat-mdc-slide-toggle-disabled-interactive');
|
||
|
|
|
||
|
|
testComponent.disabledInteractive = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(buttonElement.disabled).toBe(false);
|
||
|
|
expect(buttonElement.getAttribute('aria-disabled')).toBe('true');
|
||
|
|
expect(buttonElement.getAttribute('tabindex')).toBe('0');
|
||
|
|
expect(buttonElement.classList).toContain('mat-mdc-slide-toggle-disabled-interactive');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should not change its state when clicked while disabled and interactive', fakeAsync(() => {
|
||
|
|
expect(slideToggle.checked).toBe(false);
|
||
|
|
|
||
|
|
testComponent.isDisabled = testComponent.disabledInteractive = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
buttonElement.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
tick();
|
||
|
|
|
||
|
|
expect(slideToggle.checked).toBe(false);
|
||
|
|
}));
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('custom template', () => {
|
||
|
|
it('should not trigger the change event on initialization', fakeAsync(() => {
|
||
|
|
const fixture = TestBed.createComponent(SlideToggleBasic);
|
||
|
|
|
||
|
|
fixture.componentInstance.slideChecked = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(fixture.componentInstance.lastEvent).toBeFalsy();
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should be able to set the tabindex via the native attribute', fakeAsync(() => {
|
||
|
|
const fixture = TestBed.createComponent(SlideToggleWithTabindexAttr);
|
||
|
|
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const slideToggle = fixture.debugElement.query(By.directive(MatSlideToggle))!
|
||
|
|
.componentInstance as MatSlideToggle;
|
||
|
|
|
||
|
|
expect(slideToggle.tabIndex)
|
||
|
|
.withContext('Expected tabIndex property to have been set based on the native attribute')
|
||
|
|
.toBe(5);
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should add the disabled class if disabled through attribute', fakeAsync(() => {
|
||
|
|
const fixture = TestBed.createComponent(SlideToggleCheckedAndDisabledAttr);
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const switchEl = fixture.nativeElement.querySelector('.mdc-switch');
|
||
|
|
expect(switchEl.classList).toContain('mdc-switch--disabled');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should add the checked class if checked through attribute', fakeAsync(() => {
|
||
|
|
const fixture = TestBed.createComponent(SlideToggleCheckedAndDisabledAttr);
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const switchEl = fixture.nativeElement.querySelector('.mdc-switch');
|
||
|
|
expect(switchEl.classList).toContain('mdc-switch--checked');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should remove the tabindex from the host node', fakeAsync(() => {
|
||
|
|
const fixture = TestBed.createComponent(SlideToggleWithTabindexAttr);
|
||
|
|
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const slideToggle = fixture.debugElement.query(By.directive(MatSlideToggle))!.nativeElement;
|
||
|
|
expect(slideToggle.hasAttribute('tabindex')).toBe(false);
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should remove the tabindex from the host element when disabled', fakeAsync(() => {
|
||
|
|
const fixture = TestBed.createComponent(SlideToggleWithTabindexAttr);
|
||
|
|
|
||
|
|
fixture.componentInstance.disabled = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const slideToggle = fixture.debugElement.query(By.directive(MatSlideToggle))!.nativeElement;
|
||
|
|
expect(slideToggle.hasAttribute('tabindex')).toBe(false);
|
||
|
|
}));
|
||
|
|
});
|
||
|
|
|
||
|
|
it(
|
||
|
|
'should not change value on click when click action is noop when using custom a ' +
|
||
|
|
'action configuration',
|
||
|
|
fakeAsync(() => {
|
||
|
|
TestBed.resetTestingModule().configureTestingModule({
|
||
|
|
imports: [MatSlideToggleModule, SlideToggleBasic],
|
||
|
|
providers: [
|
||
|
|
{
|
||
|
|
provide: MAT_SLIDE_TOGGLE_DEFAULT_OPTIONS,
|
||
|
|
useValue: {disableToggleValue: true},
|
||
|
|
},
|
||
|
|
],
|
||
|
|
});
|
||
|
|
const fixture = TestBed.createComponent(SlideToggleBasic);
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const testComponent = fixture.debugElement.componentInstance;
|
||
|
|
const slideToggleDebug = fixture.debugElement.query(By.css('mat-slide-toggle'))!;
|
||
|
|
|
||
|
|
const slideToggle = slideToggleDebug.componentInstance;
|
||
|
|
const buttonElement = fixture.debugElement.query(By.css('button'))!.nativeElement;
|
||
|
|
const labelElement = fixture.debugElement.query(By.css('label'))!.nativeElement;
|
||
|
|
|
||
|
|
expect(testComponent.toggleTriggered).toBe(0);
|
||
|
|
expect(testComponent.dragTriggered).toBe(0);
|
||
|
|
expect(slideToggle.checked).withContext('Expect slide toggle value not changed').toBe(false);
|
||
|
|
|
||
|
|
labelElement.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
tick();
|
||
|
|
|
||
|
|
expect(slideToggle.checked).withContext('Expect slide toggle value not changed').toBe(false);
|
||
|
|
expect(testComponent.toggleTriggered).withContext('Expect toggle once').toBe(1);
|
||
|
|
expect(testComponent.dragTriggered).toBe(0);
|
||
|
|
|
||
|
|
buttonElement.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
tick();
|
||
|
|
|
||
|
|
expect(slideToggle.checked).withContext('Expect slide toggle value not changed').toBe(false);
|
||
|
|
expect(testComponent.toggleTriggered).withContext('Expect toggle twice').toBe(2);
|
||
|
|
expect(testComponent.dragTriggered).toBe(0);
|
||
|
|
}),
|
||
|
|
);
|
||
|
|
|
||
|
|
it('should be able to change the default color', () => {
|
||
|
|
TestBed.resetTestingModule().configureTestingModule({
|
||
|
|
imports: [MatSlideToggleModule, SlideToggleWithForm],
|
||
|
|
providers: [{provide: MAT_SLIDE_TOGGLE_DEFAULT_OPTIONS, useValue: {color: 'warn'}}],
|
||
|
|
});
|
||
|
|
const fixture = TestBed.createComponent(SlideToggleWithForm);
|
||
|
|
fixture.detectChanges();
|
||
|
|
const slideToggle = fixture.nativeElement.querySelector('.mat-mdc-slide-toggle');
|
||
|
|
expect(slideToggle.classList).toContain('mat-warn');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should clear static aria attributes from the host node', () => {
|
||
|
|
const fixture = TestBed.createComponent(SlideToggleWithStaticAriaAttributes);
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const host: HTMLElement = fixture.nativeElement.querySelector('mat-slide-toggle');
|
||
|
|
expect(host.hasAttribute('aria-label')).toBe(false);
|
||
|
|
expect(host.hasAttribute('aria-labelledby')).toBe(false);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('MatSlideToggle with forms', () => {
|
||
|
|
beforeEach(() => {
|
||
|
|
TestBed.configureTestingModule({
|
||
|
|
imports: [
|
||
|
|
MatSlideToggleModule,
|
||
|
|
FormsModule,
|
||
|
|
ReactiveFormsModule,
|
||
|
|
SlideToggleWithForm,
|
||
|
|
SlideToggleWithModel,
|
||
|
|
SlideToggleWithFormControl,
|
||
|
|
SlideToggleWithModelAndChangeEvent,
|
||
|
|
],
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('using ngModel', () => {
|
||
|
|
let fixture: ComponentFixture<SlideToggleWithModel>;
|
||
|
|
|
||
|
|
let testComponent: SlideToggleWithModel;
|
||
|
|
let slideToggle: MatSlideToggle;
|
||
|
|
let slideToggleElement: HTMLElement;
|
||
|
|
let slideToggleModel: NgModel;
|
||
|
|
let buttonElement: HTMLButtonElement;
|
||
|
|
let labelElement: HTMLLabelElement;
|
||
|
|
|
||
|
|
// This initialization is async() because it needs to wait for ngModel to set the initial value.
|
||
|
|
beforeEach(() => {
|
||
|
|
fixture = TestBed.createComponent(SlideToggleWithModel);
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const slideToggleDebug = fixture.debugElement.query(By.directive(MatSlideToggle))!;
|
||
|
|
|
||
|
|
testComponent = fixture.debugElement.componentInstance;
|
||
|
|
slideToggle = slideToggleDebug.componentInstance;
|
||
|
|
slideToggleElement = slideToggleDebug.nativeElement;
|
||
|
|
slideToggleModel = slideToggleDebug.injector.get<NgModel>(NgModel);
|
||
|
|
buttonElement = fixture.debugElement.query(By.css('button'))!.nativeElement;
|
||
|
|
labelElement = fixture.debugElement.query(By.css('label'))!.nativeElement;
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should be initially set to ng-pristine', () => {
|
||
|
|
expect(slideToggleElement.classList).toContain('ng-pristine');
|
||
|
|
expect(slideToggleElement.classList).not.toContain('ng-dirty');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should update the model programmatically', fakeAsync(() => {
|
||
|
|
expect(slideToggleElement.classList).not.toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
|
||
|
|
testComponent.modelValue = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
// Flush the microtasks because the forms module updates the model state asynchronously.
|
||
|
|
flushMicrotasks();
|
||
|
|
|
||
|
|
fixture.detectChanges();
|
||
|
|
expect(slideToggleElement.classList).toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should have the correct control state initially and after interaction', fakeAsync(() => {
|
||
|
|
// The control should start off valid, pristine, and untouched.
|
||
|
|
expect(slideToggleModel.valid).toBe(true);
|
||
|
|
expect(slideToggleModel.pristine).toBe(true);
|
||
|
|
expect(slideToggleModel.touched).toBe(false);
|
||
|
|
|
||
|
|
// After changing the value from the view, the control should
|
||
|
|
// become dirty (not pristine), but remain untouched if focus is still there.
|
||
|
|
slideToggle.checked = true;
|
||
|
|
|
||
|
|
dispatchFakeEvent(buttonElement, 'focus');
|
||
|
|
buttonElement.click();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
expect(slideToggleModel.valid).toBe(true);
|
||
|
|
expect(slideToggleModel.pristine).toBe(false);
|
||
|
|
expect(slideToggleModel.touched).toBe(false);
|
||
|
|
|
||
|
|
// Once the button element loses focus, the control should remain dirty but should
|
||
|
|
// also turn touched.
|
||
|
|
dispatchFakeEvent(buttonElement, 'blur');
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
expect(slideToggleModel.valid).toBe(true);
|
||
|
|
expect(slideToggleModel.pristine).toBe(false);
|
||
|
|
expect(slideToggleModel.touched).toBe(true);
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should not throw an error when disabling while focused', fakeAsync(() => {
|
||
|
|
expect(() => {
|
||
|
|
// Focus the button element because after disabling, the `blur` event should automatically
|
||
|
|
// fire and not result in a changed after checked exception. Related: #12323
|
||
|
|
buttonElement.focus();
|
||
|
|
tick();
|
||
|
|
|
||
|
|
fixture.componentInstance.isDisabled = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
flush();
|
||
|
|
}).not.toThrow();
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should not set the control to touched when changing the state programmatically', fakeAsync(() => {
|
||
|
|
// The control should start off with being untouched.
|
||
|
|
expect(slideToggleModel.touched).toBe(false);
|
||
|
|
|
||
|
|
testComponent.isChecked = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(slideToggleModel.touched).toBe(false);
|
||
|
|
expect(slideToggleElement.classList).toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
|
||
|
|
// Once the button element loses focus, the control should remain dirty but should
|
||
|
|
// also turn touched.
|
||
|
|
dispatchFakeEvent(buttonElement, 'blur');
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
expect(slideToggleModel.touched).toBe(true);
|
||
|
|
expect(slideToggleElement.classList).toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should not set the control to touched when changing the model', fakeAsync(() => {
|
||
|
|
// The control should start off with being untouched.
|
||
|
|
expect(slideToggleModel.touched).toBe(false);
|
||
|
|
|
||
|
|
testComponent.modelValue = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
// Flush the microtasks because the forms module updates the model state asynchronously.
|
||
|
|
flushMicrotasks();
|
||
|
|
|
||
|
|
// The checked property has been updated from the model and now the view needs
|
||
|
|
// to reflect the state change.
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(slideToggleModel.touched).toBe(false);
|
||
|
|
expect(slideToggle.checked).toBe(true);
|
||
|
|
expect(slideToggleElement.classList).toContain('mat-mdc-slide-toggle-checked');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should update checked state on click if control is checked initially', fakeAsync(() => {
|
||
|
|
fixture = TestBed.createComponent(SlideToggleWithModel);
|
||
|
|
slideToggle = fixture.debugElement.query(By.directive(MatSlideToggle))!.componentInstance;
|
||
|
|
labelElement = fixture.debugElement.query(By.css('label'))!.nativeElement;
|
||
|
|
|
||
|
|
fixture.componentInstance.modelValue = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
// Flush the microtasks because the forms module updates the model state asynchronously.
|
||
|
|
flushMicrotasks();
|
||
|
|
|
||
|
|
// Now the new checked variable has been updated in the slide-toggle and the slide-toggle
|
||
|
|
// is marked for check because it still needs to update the underlying button.
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(slideToggle.checked)
|
||
|
|
.withContext('Expected slide-toggle to be checked initially')
|
||
|
|
.toBe(true);
|
||
|
|
|
||
|
|
labelElement.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
tick();
|
||
|
|
|
||
|
|
expect(slideToggle.checked)
|
||
|
|
.withContext('Expected slide-toggle to be no longer checked after label click.')
|
||
|
|
.toBe(false);
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should be pristine if initial value is set from NgModel', fakeAsync(() => {
|
||
|
|
fixture = TestBed.createComponent(SlideToggleWithModel);
|
||
|
|
|
||
|
|
fixture.componentInstance.modelValue = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
const debugElement = fixture.debugElement.query(By.directive(MatSlideToggle))!;
|
||
|
|
const modelInstance = debugElement.injector.get<NgModel>(NgModel);
|
||
|
|
|
||
|
|
// Flush the microtasks because the forms module updates the model state asynchronously.
|
||
|
|
flushMicrotasks();
|
||
|
|
|
||
|
|
expect(modelInstance.pristine).toBe(true);
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should set the model value when toggling via the `toggle` method', fakeAsync(() => {
|
||
|
|
expect(testComponent.modelValue).toBe(false);
|
||
|
|
|
||
|
|
fixture.debugElement.query(By.directive(MatSlideToggle))!.componentInstance.toggle();
|
||
|
|
fixture.detectChanges();
|
||
|
|
flushMicrotasks();
|
||
|
|
|
||
|
|
fixture.detectChanges();
|
||
|
|
expect(testComponent.modelValue).toBe(true);
|
||
|
|
}));
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('with a FormControl', () => {
|
||
|
|
let fixture: ComponentFixture<SlideToggleWithFormControl>;
|
||
|
|
|
||
|
|
let testComponent: SlideToggleWithFormControl;
|
||
|
|
let slideToggle: MatSlideToggle;
|
||
|
|
let buttonElement: HTMLButtonElement;
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
fixture = TestBed.createComponent(SlideToggleWithFormControl);
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
testComponent = fixture.debugElement.componentInstance;
|
||
|
|
slideToggle = fixture.debugElement.query(By.directive(MatSlideToggle))!.componentInstance;
|
||
|
|
buttonElement = fixture.debugElement.query(By.css('button'))!.nativeElement;
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should toggle the disabled state', () => {
|
||
|
|
expect(slideToggle.disabled).toBe(false);
|
||
|
|
expect(buttonElement.disabled).toBe(false);
|
||
|
|
|
||
|
|
testComponent.formControl.disable();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(slideToggle.disabled).toBe(true);
|
||
|
|
expect(buttonElement.disabled).toBe(true);
|
||
|
|
|
||
|
|
testComponent.formControl.enable();
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
expect(slideToggle.disabled).toBe(false);
|
||
|
|
expect(buttonElement.disabled).toBe(false);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('with form element', () => {
|
||
|
|
let fixture: ComponentFixture<any>;
|
||
|
|
let testComponent: SlideToggleWithForm;
|
||
|
|
let buttonElement: HTMLButtonElement;
|
||
|
|
|
||
|
|
// This initialization is async() because it needs to wait for ngModel to set the initial value.
|
||
|
|
beforeEach(fakeAsync(() => {
|
||
|
|
fixture = TestBed.createComponent(SlideToggleWithForm);
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
testComponent = fixture.debugElement.componentInstance;
|
||
|
|
buttonElement = fixture.debugElement.query(By.css('button'))!.nativeElement;
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should not submit the form when clicked', fakeAsync(() => {
|
||
|
|
expect(testComponent.isSubmitted).toBe(false);
|
||
|
|
|
||
|
|
buttonElement.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
expect(testComponent.isSubmitted).toBe(false);
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should have proper invalid state if unchecked', fakeAsync(() => {
|
||
|
|
testComponent.isRequired = true;
|
||
|
|
fixture.changeDetectorRef.markForCheck();
|
||
|
|
fixture.detectChanges();
|
||
|
|
flushMicrotasks();
|
||
|
|
|
||
|
|
const slideToggleEl = fixture.nativeElement.querySelector('.mat-mdc-slide-toggle');
|
||
|
|
|
||
|
|
expect(slideToggleEl.classList).toContain('ng-invalid');
|
||
|
|
expect(slideToggleEl.classList).not.toContain('ng-valid');
|
||
|
|
|
||
|
|
// The required slide-toggle will be checked and the form control
|
||
|
|
// should become valid.
|
||
|
|
buttonElement.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
expect(slideToggleEl.classList).not.toContain('ng-invalid');
|
||
|
|
expect(slideToggleEl.classList).toContain('ng-valid');
|
||
|
|
|
||
|
|
// The required slide-toggle will be unchecked and the form control
|
||
|
|
// should become invalid.
|
||
|
|
buttonElement.click();
|
||
|
|
fixture.detectChanges();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
expect(slideToggleEl.classList).toContain('ng-invalid');
|
||
|
|
expect(slideToggleEl.classList).not.toContain('ng-valid');
|
||
|
|
}));
|
||
|
|
|
||
|
|
it('should clear static name attribute from the slide toggle host node', () => {
|
||
|
|
const hostNode = fixture.nativeElement.querySelector('.mat-mdc-slide-toggle');
|
||
|
|
expect(buttonElement.getAttribute('name')).toBeTruthy();
|
||
|
|
expect(hostNode.hasAttribute('name')).toBe(false);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('with model and change event', () => {
|
||
|
|
it('should report changes to NgModel before emitting change event', fakeAsync(() => {
|
||
|
|
const fixture = TestBed.createComponent(SlideToggleWithModelAndChangeEvent);
|
||
|
|
fixture.detectChanges();
|
||
|
|
|
||
|
|
const labelEl = fixture.debugElement.query(By.css('label'))!.nativeElement;
|
||
|
|
|
||
|
|
spyOn(fixture.componentInstance, 'onChange').and.callFake(() => {
|
||
|
|
expect(fixture.componentInstance.checked)
|
||
|
|
.withContext('Expected the model value to have changed before the change event fired.')
|
||
|
|
.toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
labelEl.click();
|
||
|
|
flush();
|
||
|
|
|
||
|
|
expect(fixture.componentInstance.onChange).toHaveBeenCalledTimes(1);
|
||
|
|
}));
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `
|
||
|
|
<mat-slide-toggle
|
||
|
|
[dir]="direction"
|
||
|
|
[required]="isRequired"
|
||
|
|
[disabled]="isDisabled"
|
||
|
|
[color]="slideColor"
|
||
|
|
[id]="slideId"
|
||
|
|
[checked]="slideChecked"
|
||
|
|
[name]="slideName"
|
||
|
|
[aria-label]="slideLabel"
|
||
|
|
[aria-labelledby]="slideLabelledBy"
|
||
|
|
[aria-describedby]="slideAriaDescribedBy"
|
||
|
|
[tabIndex]="slideTabindex"
|
||
|
|
[labelPosition]="labelPosition"
|
||
|
|
[disableRipple]="disableRipple"
|
||
|
|
[hideIcon]="hideIcon"
|
||
|
|
[disabledInteractive]="disabledInteractive"
|
||
|
|
(toggleChange)="onSlideToggleChange()"
|
||
|
|
(dragChange)="onSlideDragChange()"
|
||
|
|
(change)="onSlideChange($event)"
|
||
|
|
(click)="onSlideClick($event)">
|
||
|
|
<span>Test Slide Toggle</span>
|
||
|
|
</mat-slide-toggle>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatSlideToggleModule, BidiModule],
|
||
|
|
})
|
||
|
|
class SlideToggleBasic {
|
||
|
|
isDisabled = false;
|
||
|
|
isRequired = false;
|
||
|
|
disableRipple = false;
|
||
|
|
slideChecked = false;
|
||
|
|
slideColor: string;
|
||
|
|
slideId: string | null;
|
||
|
|
slideName: string | null;
|
||
|
|
slideLabel: string | null;
|
||
|
|
slideLabelledBy: string | null;
|
||
|
|
slideAriaDescribedBy: string | null;
|
||
|
|
slideTabindex: number;
|
||
|
|
lastEvent: MatSlideToggleChange;
|
||
|
|
labelPosition: string;
|
||
|
|
toggleTriggered = 0;
|
||
|
|
dragTriggered = 0;
|
||
|
|
direction: Direction = 'ltr';
|
||
|
|
hideIcon = false;
|
||
|
|
disabledInteractive = false;
|
||
|
|
|
||
|
|
onSlideClick: (event?: Event) => void = () => {};
|
||
|
|
onSlideChange = (event: MatSlideToggleChange) => (this.lastEvent = event);
|
||
|
|
onSlideToggleChange = () => this.toggleTriggered++;
|
||
|
|
onSlideDragChange = () => this.dragTriggered++;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `
|
||
|
|
<form ngNativeValidate (ngSubmit)="isSubmitted = true">
|
||
|
|
<mat-slide-toggle name="slide" ngModel [required]="isRequired">Required</mat-slide-toggle>
|
||
|
|
<button type="submit"></button>
|
||
|
|
</form>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatSlideToggleModule, FormsModule, ReactiveFormsModule],
|
||
|
|
})
|
||
|
|
class SlideToggleWithForm {
|
||
|
|
isSubmitted: boolean = false;
|
||
|
|
isRequired: boolean = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `<mat-slide-toggle [(ngModel)]="modelValue" [disabled]="isDisabled"
|
||
|
|
[checked]="isChecked"></mat-slide-toggle>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatSlideToggleModule, FormsModule, ReactiveFormsModule],
|
||
|
|
})
|
||
|
|
class SlideToggleWithModel {
|
||
|
|
modelValue = false;
|
||
|
|
isChecked = false;
|
||
|
|
isDisabled = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `<mat-slide-toggle checked disabled>Label</mat-slide-toggle>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatSlideToggleModule, BidiModule],
|
||
|
|
})
|
||
|
|
class SlideToggleCheckedAndDisabledAttr {}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `
|
||
|
|
<mat-slide-toggle [formControl]="formControl">
|
||
|
|
<span>Test Slide Toggle</span>
|
||
|
|
</mat-slide-toggle>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatSlideToggleModule, FormsModule, ReactiveFormsModule],
|
||
|
|
})
|
||
|
|
class SlideToggleWithFormControl {
|
||
|
|
formControl = new FormControl(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `<mat-slide-toggle tabindex="5" [disabled]="disabled"></mat-slide-toggle>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatSlideToggleModule, BidiModule],
|
||
|
|
})
|
||
|
|
class SlideToggleWithTabindexAttr {
|
||
|
|
disabled = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `<mat-slide-toggle>{{label}}</mat-slide-toggle>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatSlideToggleModule, BidiModule],
|
||
|
|
})
|
||
|
|
class SlideToggleWithoutLabel {
|
||
|
|
label: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `<mat-slide-toggle [(ngModel)]="checked" (change)="onChange()"></mat-slide-toggle>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatSlideToggleModule, FormsModule, ReactiveFormsModule],
|
||
|
|
})
|
||
|
|
class SlideToggleWithModelAndChangeEvent {
|
||
|
|
checked: boolean;
|
||
|
|
onChange: () => void = () => {};
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `<mat-slide-toggle><some-text></some-text></mat-slide-toggle>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatSlideToggleModule, BidiModule],
|
||
|
|
})
|
||
|
|
class SlideToggleProjectedLabel {}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
selector: 'some-text',
|
||
|
|
template: `<span>{{text}}</span>`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatSlideToggleModule, BidiModule],
|
||
|
|
})
|
||
|
|
class TextBindingComponent {
|
||
|
|
text: string = 'Some text';
|
||
|
|
}
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
template: `
|
||
|
|
<mat-slide-toggle aria-label="Slide toggle" aria-labelledby="something"></mat-slide-toggle>
|
||
|
|
`,
|
||
|
|
standalone: true,
|
||
|
|
imports: [MatSlideToggleModule, BidiModule],
|
||
|
|
})
|
||
|
|
class SlideToggleWithStaticAriaAttributes {}
|