1332 lines
47 KiB
TypeScript
1332 lines
47 KiB
TypeScript
import {dispatchMouseEvent} from '@angular/cdk/testing/private';
|
|
import {Component, DebugElement, QueryList, ViewChild, ViewChildren} from '@angular/core';
|
|
import {ComponentFixture, TestBed, fakeAsync, flush, tick} from '@angular/core/testing';
|
|
import {FormControl, FormsModule, NgModel, ReactiveFormsModule} from '@angular/forms';
|
|
import {By} from '@angular/platform-browser';
|
|
import {
|
|
MAT_BUTTON_TOGGLE_DEFAULT_OPTIONS,
|
|
MatButtonToggle,
|
|
MatButtonToggleChange,
|
|
MatButtonToggleGroup,
|
|
MatButtonToggleModule,
|
|
} from './index';
|
|
|
|
describe('MatButtonToggle with forms', () => {
|
|
beforeEach(fakeAsync(() => {
|
|
TestBed.configureTestingModule({
|
|
imports: [
|
|
MatButtonToggleModule,
|
|
FormsModule,
|
|
ReactiveFormsModule,
|
|
ButtonToggleGroupWithNgModel,
|
|
ButtonToggleGroupWithFormControl,
|
|
ButtonToggleGroupWithIndirectDescendantToggles,
|
|
ButtonToggleGroupWithFormControlAndDynamicButtons,
|
|
],
|
|
});
|
|
}));
|
|
|
|
describe('using FormControl', () => {
|
|
let fixture: ComponentFixture<ButtonToggleGroupWithFormControl>;
|
|
let groupDebugElement: DebugElement;
|
|
let groupInstance: MatButtonToggleGroup;
|
|
let testComponent: ButtonToggleGroupWithFormControl;
|
|
|
|
beforeEach(fakeAsync(() => {
|
|
fixture = TestBed.createComponent(ButtonToggleGroupWithFormControl);
|
|
fixture.detectChanges();
|
|
|
|
testComponent = fixture.debugElement.componentInstance;
|
|
|
|
groupDebugElement = fixture.debugElement.query(By.directive(MatButtonToggleGroup))!;
|
|
groupInstance = groupDebugElement.injector.get<MatButtonToggleGroup>(MatButtonToggleGroup);
|
|
}));
|
|
|
|
it('should toggle the disabled state', () => {
|
|
testComponent.control.disable();
|
|
|
|
expect(groupInstance.disabled).toBe(true);
|
|
|
|
testComponent.control.enable();
|
|
|
|
expect(groupInstance.disabled).toBe(false);
|
|
});
|
|
|
|
it('should set the value', () => {
|
|
testComponent.control.setValue('green');
|
|
|
|
expect(groupInstance.value).toBe('green');
|
|
|
|
testComponent.control.setValue('red');
|
|
|
|
expect(groupInstance.value).toBe('red');
|
|
});
|
|
|
|
it('should register the on change callback', () => {
|
|
const spy = jasmine.createSpy('onChange callback');
|
|
|
|
testComponent.control.registerOnChange(spy);
|
|
testComponent.control.setValue('blue');
|
|
|
|
expect(spy).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('button toggle group with ngModel and change event', () => {
|
|
let fixture: ComponentFixture<ButtonToggleGroupWithNgModel>;
|
|
let groupDebugElement: DebugElement;
|
|
let buttonToggleDebugElements: DebugElement[];
|
|
let groupInstance: MatButtonToggleGroup;
|
|
let buttonToggleInstances: MatButtonToggle[];
|
|
let testComponent: ButtonToggleGroupWithNgModel;
|
|
let groupNgModel: NgModel;
|
|
let innerButtons: HTMLElement[];
|
|
|
|
beforeEach(() => {
|
|
fixture = TestBed.createComponent(ButtonToggleGroupWithNgModel);
|
|
fixture.detectChanges();
|
|
testComponent = fixture.debugElement.componentInstance;
|
|
|
|
groupDebugElement = fixture.debugElement.query(By.directive(MatButtonToggleGroup))!;
|
|
groupInstance = groupDebugElement.injector.get<MatButtonToggleGroup>(MatButtonToggleGroup);
|
|
groupNgModel = groupDebugElement.injector.get<NgModel>(NgModel);
|
|
|
|
buttonToggleDebugElements = fixture.debugElement.queryAll(By.directive(MatButtonToggle));
|
|
buttonToggleInstances = buttonToggleDebugElements.map(debugEl => debugEl.componentInstance);
|
|
innerButtons = buttonToggleDebugElements.map(
|
|
debugEl => debugEl.query(By.css('button'))!.nativeElement,
|
|
);
|
|
});
|
|
|
|
it('should update the model before firing change event', fakeAsync(() => {
|
|
expect(testComponent.modelValue).toBeUndefined();
|
|
expect(testComponent.lastEvent).toBeUndefined();
|
|
|
|
innerButtons[0].click();
|
|
fixture.detectChanges();
|
|
|
|
tick();
|
|
expect(testComponent.modelValue).toBe('red');
|
|
expect(testComponent.lastEvent.value).toBe('red');
|
|
}));
|
|
|
|
it('should set individual radio names based on the group name', () => {
|
|
expect(groupInstance.name).toBeTruthy();
|
|
for (let buttonToggle of innerButtons) {
|
|
expect(buttonToggle.getAttribute('name')).toBe(groupInstance.name);
|
|
}
|
|
|
|
groupInstance.name = 'new name';
|
|
fixture.detectChanges();
|
|
|
|
for (let buttonToggle of innerButtons) {
|
|
expect(buttonToggle.getAttribute('name')).toBe(groupInstance.name);
|
|
}
|
|
});
|
|
|
|
it('should update the name of radio DOM elements if the name of the group changes', () => {
|
|
expect(innerButtons.every(button => button.getAttribute('name') === groupInstance.name))
|
|
.withContext('Expected all buttons to have the initial name.')
|
|
.toBe(true);
|
|
|
|
fixture.componentInstance.groupName = 'changed-name';
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupInstance.name).toBe('changed-name');
|
|
expect(innerButtons.every(button => button.getAttribute('name') === groupInstance.name))
|
|
.withContext('Expected all buttons to have the new name.')
|
|
.toBe(true);
|
|
});
|
|
|
|
it('should set the name of the buttons to the group name if the name of the button changes after init', () => {
|
|
const firstButton = innerButtons[0];
|
|
expect(firstButton.getAttribute('name')).toBe(fixture.componentInstance.groupName);
|
|
|
|
fixture.componentInstance.options[0].name = 'changed-name';
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
expect(firstButton.getAttribute('name')).toBe(fixture.componentInstance.groupName);
|
|
});
|
|
|
|
it('should check the corresponding button toggle on a group value change', () => {
|
|
expect(groupInstance.value).toBeFalsy();
|
|
for (let buttonToggle of buttonToggleInstances) {
|
|
expect(buttonToggle.checked).toBeFalsy();
|
|
}
|
|
|
|
groupInstance.value = 'red';
|
|
for (let buttonToggle of buttonToggleInstances) {
|
|
expect(buttonToggle.checked).toBe(groupInstance.value === buttonToggle.value);
|
|
}
|
|
|
|
const selected = groupInstance.selected as MatButtonToggle;
|
|
|
|
expect(selected.value).toBe(groupInstance.value);
|
|
});
|
|
|
|
it('should have the correct FormControl state initially and after interaction', fakeAsync(() => {
|
|
expect(groupNgModel.valid).toBe(true);
|
|
expect(groupNgModel.pristine).toBe(true);
|
|
expect(groupNgModel.touched).toBe(false);
|
|
|
|
buttonToggleInstances[1].checked = true;
|
|
fixture.detectChanges();
|
|
tick();
|
|
|
|
expect(groupNgModel.valid).toBe(true);
|
|
expect(groupNgModel.pristine).toBe(true);
|
|
expect(groupNgModel.touched).toBe(false);
|
|
|
|
innerButtons[2].click();
|
|
fixture.detectChanges();
|
|
tick();
|
|
|
|
expect(groupNgModel.valid).toBe(true);
|
|
expect(groupNgModel.pristine).toBe(false);
|
|
expect(groupNgModel.touched).toBe(true);
|
|
}));
|
|
|
|
it('should update the ngModel value when selecting a button toggle', fakeAsync(() => {
|
|
innerButtons[1].click();
|
|
fixture.detectChanges();
|
|
|
|
tick();
|
|
|
|
expect(testComponent.modelValue).toBe('green');
|
|
}));
|
|
|
|
it('should show a ripple on label click', () => {
|
|
const groupElement = groupDebugElement.nativeElement;
|
|
|
|
expect(groupElement.querySelectorAll('.mat-ripple-element').length).toBe(0);
|
|
|
|
dispatchMouseEvent(innerButtons[0], 'mousedown');
|
|
dispatchMouseEvent(innerButtons[0], 'mouseup');
|
|
|
|
expect(groupElement.querySelectorAll('.mat-ripple-element').length).toBe(1);
|
|
});
|
|
|
|
it('should allow ripples to be disabled', () => {
|
|
const groupElement = groupDebugElement.nativeElement;
|
|
|
|
testComponent.disableRipple = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupElement.querySelectorAll('.mat-ripple-element').length).toBe(0);
|
|
|
|
dispatchMouseEvent(innerButtons[0], 'mousedown');
|
|
dispatchMouseEvent(innerButtons[0], 'mouseup');
|
|
|
|
expect(groupElement.querySelectorAll('.mat-ripple-element').length).toBe(0);
|
|
});
|
|
|
|
it(
|
|
'should maintain the selected value when swapping out the list of toggles with one ' +
|
|
'that still contains the value',
|
|
fakeAsync(() => {
|
|
expect(buttonToggleInstances[0].checked).toBe(false);
|
|
expect(fixture.componentInstance.modelValue).toBeFalsy();
|
|
expect(groupInstance.value).toBeFalsy();
|
|
|
|
groupInstance.value = 'red';
|
|
fixture.detectChanges();
|
|
|
|
expect(buttonToggleInstances[0].checked).toBe(true);
|
|
expect(groupInstance.value).toBe('red');
|
|
|
|
fixture.componentInstance.options = [...fixture.componentInstance.options];
|
|
fixture.detectChanges();
|
|
tick();
|
|
fixture.detectChanges();
|
|
|
|
buttonToggleDebugElements = fixture.debugElement.queryAll(By.directive(MatButtonToggle));
|
|
buttonToggleInstances = buttonToggleDebugElements.map(debugEl => debugEl.componentInstance);
|
|
|
|
expect(buttonToggleInstances[0].checked).toBe(true);
|
|
expect(groupInstance.value).toBe('red');
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('should be able to pick up toggles that are not direct descendants', fakeAsync(() => {
|
|
const fixture = TestBed.createComponent(ButtonToggleGroupWithIndirectDescendantToggles);
|
|
fixture.detectChanges();
|
|
|
|
const button = fixture.nativeElement.querySelector('.mat-button-toggle button');
|
|
const groupDebugElement = fixture.debugElement.query(By.directive(MatButtonToggleGroup))!;
|
|
const groupInstance =
|
|
groupDebugElement.injector.get<MatButtonToggleGroup>(MatButtonToggleGroup);
|
|
|
|
button.click();
|
|
fixture.detectChanges();
|
|
tick();
|
|
|
|
expect(groupInstance.value).toBe('red');
|
|
expect(fixture.componentInstance.control.value).toBe('red');
|
|
expect(groupInstance._buttonToggles.length).toBe(3);
|
|
}));
|
|
|
|
it('should preserve the selection if the pre-selected option is removed and re-added', () => {
|
|
const fixture = TestBed.createComponent(ButtonToggleGroupWithFormControlAndDynamicButtons);
|
|
const instance = fixture.componentInstance;
|
|
instance.control.setValue('a');
|
|
fixture.detectChanges();
|
|
const buttons = fixture.nativeElement.querySelectorAll('.mat-button-toggle-button');
|
|
|
|
expect(instance.toggles.map(t => t.checked)).toEqual([true, false, false]);
|
|
|
|
buttons[2].click();
|
|
fixture.detectChanges();
|
|
|
|
instance.values.shift();
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
expect(instance.toggles.map(t => t.checked)).toEqual([false, true]);
|
|
|
|
instance.values.unshift('a');
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(instance.toggles.map(t => t.checked)).toEqual([false, false, true]);
|
|
});
|
|
|
|
it('should preserve the pre-selected option if it is removed and re-added', () => {
|
|
const fixture = TestBed.createComponent(ButtonToggleGroupWithFormControlAndDynamicButtons);
|
|
const instance = fixture.componentInstance;
|
|
instance.control.setValue('a');
|
|
fixture.detectChanges();
|
|
expect(instance.toggles.map(t => t.checked)).toEqual([true, false, false]);
|
|
|
|
instance.values.shift();
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
expect(instance.toggles.map(t => t.checked)).toEqual([false, false]);
|
|
|
|
instance.values.unshift('a');
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(instance.toggles.map(t => t.checked)).toEqual([true, false, false]);
|
|
});
|
|
|
|
it('should set the initial tabindex when using ngModel with a static list of options where none match the value', fakeAsync(() => {
|
|
const fixture = TestBed.createComponent(ButtonToggleGroupWithNgModelAndStaticOptions);
|
|
fixture.detectChanges();
|
|
tick();
|
|
const indexes = Array.from(
|
|
fixture.nativeElement.querySelectorAll('button'),
|
|
(button: HTMLElement) => button.getAttribute('tabindex'),
|
|
);
|
|
|
|
expect(indexes).toEqual(['0', '-1', '-1']);
|
|
}));
|
|
});
|
|
|
|
describe('MatButtonToggle without forms', () => {
|
|
beforeEach(fakeAsync(() => {
|
|
TestBed.configureTestingModule({
|
|
imports: [
|
|
MatButtonToggleModule,
|
|
ButtonTogglesInsideButtonToggleGroup,
|
|
ButtonTogglesInsideButtonToggleGroupMultiple,
|
|
FalsyButtonTogglesInsideButtonToggleGroupMultiple,
|
|
ButtonToggleGroupWithInitialValue,
|
|
StandaloneButtonToggle,
|
|
ButtonToggleWithAriaLabel,
|
|
ButtonToggleWithAriaLabelledby,
|
|
RepeatedButtonTogglesWithPreselectedValue,
|
|
ButtonToggleWithTabindex,
|
|
ButtonToggleWithStaticName,
|
|
ButtonToggleWithStaticChecked,
|
|
ButtonToggleWithStaticAriaAttributes,
|
|
],
|
|
});
|
|
}));
|
|
|
|
describe('inside of an exclusive selection group', () => {
|
|
let fixture: ComponentFixture<ButtonTogglesInsideButtonToggleGroup>;
|
|
let groupDebugElement: DebugElement;
|
|
let groupNativeElement: HTMLElement;
|
|
let buttonToggleDebugElements: DebugElement[];
|
|
let buttonToggleNativeElements: HTMLElement[];
|
|
let innerButtons: HTMLLabelElement[];
|
|
let groupInstance: MatButtonToggleGroup;
|
|
let buttonToggleInstances: MatButtonToggle[];
|
|
let testComponent: ButtonTogglesInsideButtonToggleGroup;
|
|
|
|
beforeEach(() => {
|
|
fixture = TestBed.createComponent(ButtonTogglesInsideButtonToggleGroup);
|
|
fixture.detectChanges();
|
|
|
|
testComponent = fixture.debugElement.componentInstance;
|
|
|
|
groupDebugElement = fixture.debugElement.query(By.directive(MatButtonToggleGroup))!;
|
|
groupNativeElement = groupDebugElement.nativeElement;
|
|
groupInstance = groupDebugElement.injector.get<MatButtonToggleGroup>(MatButtonToggleGroup);
|
|
|
|
buttonToggleDebugElements = fixture.debugElement.queryAll(By.directive(MatButtonToggle));
|
|
|
|
buttonToggleNativeElements = buttonToggleDebugElements.map(debugEl => debugEl.nativeElement);
|
|
|
|
innerButtons = fixture.debugElement
|
|
.queryAll(By.css('button'))
|
|
.map(debugEl => debugEl.nativeElement);
|
|
|
|
buttonToggleInstances = buttonToggleDebugElements.map(debugEl => debugEl.componentInstance);
|
|
});
|
|
|
|
it('should initialize the tab index correctly', () => {
|
|
expect(innerButtons.map(b => b.getAttribute('tabindex'))).toEqual(['0', '-1', '-1']);
|
|
});
|
|
|
|
it('should update the tab index correctly', () => {
|
|
innerButtons[1].click();
|
|
fixture.detectChanges();
|
|
|
|
expect(innerButtons[0].getAttribute('tabindex')).toBe('-1');
|
|
expect(innerButtons[1].getAttribute('tabindex')).toBe('0');
|
|
});
|
|
|
|
it('should set individual button toggle names based on the group name', () => {
|
|
expect(groupInstance.name).toBeTruthy();
|
|
for (let buttonToggle of innerButtons) {
|
|
expect(buttonToggle.getAttribute('name')).toBe(groupInstance.name);
|
|
}
|
|
});
|
|
|
|
it('should disable click interactions when the group is disabled', () => {
|
|
testComponent.isGroupDisabled = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
buttonToggleNativeElements[0].click();
|
|
expect(buttonToggleInstances[0].checked).toBe(false);
|
|
expect(buttonToggleInstances[0].disabled).toBe(true);
|
|
|
|
testComponent.isGroupDisabled = false;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(buttonToggleInstances[0].disabled).toBe(false);
|
|
|
|
innerButtons[0].click();
|
|
fixture.detectChanges();
|
|
|
|
expect(buttonToggleInstances[0].checked).toBe(true);
|
|
});
|
|
|
|
it('should set aria-disabled based on whether the group is disabled', () => {
|
|
expect(groupNativeElement.getAttribute('aria-disabled')).toBe('false');
|
|
|
|
testComponent.isGroupDisabled = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupNativeElement.getAttribute('aria-disabled')).toBe('true');
|
|
});
|
|
|
|
it('should disable the underlying button when the group is disabled', () => {
|
|
const buttons = buttonToggleNativeElements.map(toggle => toggle.querySelector('button')!);
|
|
|
|
expect(buttons.every(input => input.disabled)).toBe(false);
|
|
|
|
testComponent.isGroupDisabled = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(buttons.every(input => input.disabled)).toBe(true);
|
|
});
|
|
|
|
it('should be able to keep the button interactive while disabled', () => {
|
|
const button = buttonToggleNativeElements[0].querySelector('button')!;
|
|
testComponent.isGroupDisabled = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(button.hasAttribute('disabled')).toBe(true);
|
|
expect(button.hasAttribute('aria-disabled')).toBe(false);
|
|
expect(button.getAttribute('tabindex')).toBe('-1');
|
|
|
|
testComponent.disabledIntearctive = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(button.hasAttribute('disabled')).toBe(false);
|
|
expect(button.getAttribute('aria-disabled')).toBe('true');
|
|
expect(button.getAttribute('tabindex')).toBe('0');
|
|
});
|
|
|
|
it('should update the group value when one of the toggles changes', () => {
|
|
expect(groupInstance.value).toBeFalsy();
|
|
innerButtons[0].click();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupInstance.value).toBe('test1');
|
|
expect(groupInstance.selected).toBe(buttonToggleInstances[0]);
|
|
});
|
|
|
|
it('should propagate the value change back up via a two-way binding', () => {
|
|
expect(groupInstance.value).toBeFalsy();
|
|
innerButtons[0].click();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupInstance.value).toBe('test1');
|
|
expect(testComponent.groupValue).toBe('test1');
|
|
});
|
|
|
|
it('should update the group and toggles when one of the button toggles is clicked', () => {
|
|
expect(groupInstance.value).toBeFalsy();
|
|
innerButtons[0].click();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupInstance.value).toBe('test1');
|
|
expect(groupInstance.selected).toBe(buttonToggleInstances[0]);
|
|
expect(buttonToggleInstances[0].checked).toBe(true);
|
|
expect(buttonToggleInstances[1].checked).toBe(false);
|
|
|
|
innerButtons[1].click();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupInstance.value).toBe('test2');
|
|
expect(groupInstance.selected).toBe(buttonToggleInstances[1]);
|
|
expect(buttonToggleInstances[0].checked).toBe(false);
|
|
expect(buttonToggleInstances[1].checked).toBe(true);
|
|
});
|
|
|
|
it('should check a button toggle upon interaction with underlying native radio button', () => {
|
|
innerButtons[0].click();
|
|
fixture.detectChanges();
|
|
|
|
expect(buttonToggleInstances[0].checked).toBe(true);
|
|
expect(groupInstance.value).toBe('test1');
|
|
});
|
|
|
|
it('should change the vertical state', () => {
|
|
expect(groupNativeElement.classList).not.toContain('mat-button-toggle-vertical');
|
|
|
|
groupInstance.vertical = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupNativeElement.classList).toContain('mat-button-toggle-vertical');
|
|
});
|
|
|
|
it('should emit a change event from button toggles', fakeAsync(() => {
|
|
expect(buttonToggleInstances[0].checked).toBe(false);
|
|
|
|
const changeSpy = jasmine.createSpy('button-toggle change listener');
|
|
buttonToggleInstances[0].change.subscribe(changeSpy);
|
|
|
|
innerButtons[0].click();
|
|
fixture.detectChanges();
|
|
tick();
|
|
expect(changeSpy).toHaveBeenCalledTimes(1);
|
|
|
|
innerButtons[0].click();
|
|
fixture.detectChanges();
|
|
tick();
|
|
|
|
// Always emit change event when button toggle is clicked
|
|
expect(changeSpy).toHaveBeenCalledTimes(2);
|
|
}));
|
|
|
|
it('should emit a change event from the button toggle group', fakeAsync(() => {
|
|
expect(groupInstance.value).toBeFalsy();
|
|
|
|
const changeSpy = jasmine.createSpy('button-toggle-group change listener');
|
|
groupInstance.change.subscribe(changeSpy);
|
|
|
|
innerButtons[0].click();
|
|
fixture.detectChanges();
|
|
tick();
|
|
expect(changeSpy).toHaveBeenCalled();
|
|
|
|
innerButtons[1].click();
|
|
fixture.detectChanges();
|
|
tick();
|
|
expect(changeSpy).toHaveBeenCalledTimes(2);
|
|
}));
|
|
|
|
it('should update the group and button toggles when updating the group value', () => {
|
|
expect(groupInstance.value).toBeFalsy();
|
|
|
|
testComponent.groupValue = 'test1';
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupInstance.value).toBe('test1');
|
|
expect(groupInstance.selected).toBe(buttonToggleInstances[0]);
|
|
expect(buttonToggleInstances[0].checked).toBe(true);
|
|
expect(buttonToggleInstances[1].checked).toBe(false);
|
|
|
|
testComponent.groupValue = 'test2';
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupInstance.value).toBe('test2');
|
|
expect(groupInstance.selected).toBe(buttonToggleInstances[1]);
|
|
expect(buttonToggleInstances[0].checked).toBe(false);
|
|
expect(buttonToggleInstances[1].checked).toBe(true);
|
|
});
|
|
|
|
it('should deselect all of the checkboxes when the group value is cleared', () => {
|
|
buttonToggleInstances[0].checked = true;
|
|
|
|
expect(groupInstance.value).toBeTruthy();
|
|
|
|
groupInstance.value = null;
|
|
|
|
expect(buttonToggleInstances.every(toggle => !toggle.checked)).toBe(true);
|
|
});
|
|
|
|
it('should update the model if a selected toggle is removed', fakeAsync(() => {
|
|
expect(groupInstance.value).toBeFalsy();
|
|
innerButtons[0].click();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupInstance.value).toBe('test1');
|
|
expect(groupInstance.selected).toBe(buttonToggleInstances[0]);
|
|
|
|
testComponent.renderFirstToggle = false;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
tick();
|
|
|
|
expect(groupInstance.value).toBeFalsy();
|
|
expect(groupInstance.selected).toBeFalsy();
|
|
}));
|
|
|
|
it('should show checkmark indicator by default', () => {
|
|
innerButtons[0].click();
|
|
fixture.detectChanges();
|
|
|
|
expect(
|
|
fixture.nativeElement.querySelectorAll(
|
|
'.mat-button-toggle-checked .mat-button-toggle-checkbox-wrapper',
|
|
).length,
|
|
).toBe(1);
|
|
});
|
|
});
|
|
|
|
describe('with initial value and change event', () => {
|
|
it('should not fire an initial change event', () => {
|
|
const fixture = TestBed.createComponent(ButtonToggleGroupWithInitialValue);
|
|
const testComponent = fixture.debugElement.componentInstance;
|
|
const groupDebugElement = fixture.debugElement.query(By.directive(MatButtonToggleGroup))!;
|
|
const groupInstance: MatButtonToggleGroup =
|
|
groupDebugElement.injector.get<MatButtonToggleGroup>(MatButtonToggleGroup);
|
|
|
|
fixture.detectChanges();
|
|
|
|
// Note that we cast to a boolean, because the event has some circular references
|
|
// which will crash the runner when Jasmine attempts to stringify them.
|
|
expect(!!testComponent.lastEvent).toBe(false);
|
|
expect(groupInstance.value).toBe('red');
|
|
|
|
groupInstance.value = 'green';
|
|
fixture.detectChanges();
|
|
|
|
expect(!!testComponent.lastEvent).toBe(false);
|
|
expect(groupInstance.value).toBe('green');
|
|
});
|
|
});
|
|
|
|
describe('inside of a multiple selection group', () => {
|
|
let fixture: ComponentFixture<ButtonTogglesInsideButtonToggleGroupMultiple>;
|
|
let groupDebugElement: DebugElement;
|
|
let groupNativeElement: HTMLElement;
|
|
let buttonToggleDebugElements: DebugElement[];
|
|
let buttonToggleNativeElements: HTMLElement[];
|
|
let buttonToggleLabelElements: HTMLLabelElement[];
|
|
let groupInstance: MatButtonToggleGroup;
|
|
let buttonToggleInstances: MatButtonToggle[];
|
|
let testComponent: ButtonTogglesInsideButtonToggleGroupMultiple;
|
|
|
|
beforeEach(fakeAsync(() => {
|
|
fixture = TestBed.createComponent(ButtonTogglesInsideButtonToggleGroupMultiple);
|
|
fixture.detectChanges();
|
|
|
|
testComponent = fixture.debugElement.componentInstance;
|
|
|
|
groupDebugElement = fixture.debugElement.query(By.directive(MatButtonToggleGroup))!;
|
|
groupNativeElement = groupDebugElement.nativeElement;
|
|
groupInstance = groupDebugElement.injector.get<MatButtonToggleGroup>(MatButtonToggleGroup);
|
|
|
|
buttonToggleDebugElements = fixture.debugElement.queryAll(By.directive(MatButtonToggle));
|
|
buttonToggleNativeElements = buttonToggleDebugElements.map(debugEl => debugEl.nativeElement);
|
|
buttonToggleLabelElements = fixture.debugElement
|
|
.queryAll(By.css('button'))
|
|
.map(debugEl => debugEl.nativeElement);
|
|
buttonToggleInstances = buttonToggleDebugElements.map(debugEl => debugEl.componentInstance);
|
|
}));
|
|
|
|
it('should disable click interactions when the group is disabled', () => {
|
|
testComponent.isGroupDisabled = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
buttonToggleNativeElements[0].click();
|
|
expect(buttonToggleInstances[0].checked).toBe(false);
|
|
});
|
|
|
|
it('should check a button toggle when clicked', () => {
|
|
expect(buttonToggleInstances.every(buttonToggle => !buttonToggle.checked)).toBe(true);
|
|
|
|
const nativeCheckboxLabel = buttonToggleDebugElements[0].query(
|
|
By.css('button'),
|
|
)!.nativeElement;
|
|
|
|
nativeCheckboxLabel.click();
|
|
|
|
expect(groupInstance.value).toEqual(['eggs']);
|
|
expect(buttonToggleInstances[0].checked).toBe(true);
|
|
});
|
|
|
|
it('should allow for multiple toggles to be selected', () => {
|
|
buttonToggleInstances[0].checked = true;
|
|
fixture.detectChanges();
|
|
|
|
expect(groupInstance.value).toEqual(['eggs']);
|
|
expect(buttonToggleInstances[0].checked).toBe(true);
|
|
|
|
buttonToggleInstances[1].checked = true;
|
|
fixture.detectChanges();
|
|
|
|
expect(groupInstance.value).toEqual(['eggs', 'flour']);
|
|
expect(buttonToggleInstances[1].checked).toBe(true);
|
|
expect(buttonToggleInstances[0].checked).toBe(true);
|
|
});
|
|
|
|
it('should check a button toggle upon interaction with underlying native checkbox', () => {
|
|
const nativeCheckboxButton = buttonToggleDebugElements[0].query(
|
|
By.css('button'),
|
|
)!.nativeElement;
|
|
|
|
nativeCheckboxButton.click();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupInstance.value).toEqual(['eggs']);
|
|
expect(buttonToggleInstances[0].checked).toBe(true);
|
|
});
|
|
|
|
it('should change the vertical state', () => {
|
|
expect(groupNativeElement.classList).not.toContain('mat-button-toggle-vertical');
|
|
|
|
groupInstance.vertical = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(groupNativeElement.classList).toContain('mat-button-toggle-vertical');
|
|
});
|
|
|
|
it('should deselect a button toggle when selected twice', fakeAsync(() => {
|
|
buttonToggleLabelElements[0].click();
|
|
fixture.detectChanges();
|
|
tick();
|
|
|
|
expect(buttonToggleInstances[0].checked).toBe(true);
|
|
expect(groupInstance.value).toEqual(['eggs']);
|
|
|
|
buttonToggleLabelElements[0].click();
|
|
fixture.detectChanges();
|
|
tick();
|
|
|
|
expect(groupInstance.value).toEqual([]);
|
|
expect(buttonToggleInstances[0].checked).toBe(false);
|
|
}));
|
|
|
|
it('should emit a change event for state changes', fakeAsync(() => {
|
|
expect(buttonToggleInstances[0].checked).toBe(false);
|
|
|
|
const changeSpy = jasmine.createSpy('button-toggle change listener');
|
|
buttonToggleInstances[0].change.subscribe(changeSpy);
|
|
|
|
buttonToggleLabelElements[0].click();
|
|
fixture.detectChanges();
|
|
tick();
|
|
expect(changeSpy).toHaveBeenCalled();
|
|
expect(groupInstance.value).toEqual(['eggs']);
|
|
|
|
buttonToggleLabelElements[0].click();
|
|
fixture.detectChanges();
|
|
tick();
|
|
expect(groupInstance.value).toEqual([]);
|
|
|
|
// The default browser behavior is to emit an event, when the value was set
|
|
// to false. That's because the current input type is set to `checkbox` when
|
|
// using the multiple mode.
|
|
expect(changeSpy).toHaveBeenCalledTimes(2);
|
|
}));
|
|
|
|
it('should throw when attempting to assign a non-array value', () => {
|
|
expect(() => {
|
|
groupInstance.value = 'not-an-array';
|
|
}).toThrowError(/Value must be an array/);
|
|
});
|
|
|
|
it('should show checkmark indicator by default', () => {
|
|
buttonToggleLabelElements[0].click();
|
|
buttonToggleLabelElements[1].click();
|
|
fixture.detectChanges();
|
|
|
|
expect(
|
|
fixture.nativeElement.querySelectorAll(
|
|
'.mat-button-toggle-checked .mat-button-toggle-checkbox-wrapper',
|
|
).length,
|
|
).toBe(2);
|
|
});
|
|
});
|
|
|
|
describe('as standalone', () => {
|
|
let fixture: ComponentFixture<StandaloneButtonToggle>;
|
|
let buttonToggleDebugElement: DebugElement;
|
|
let buttonToggleNativeElement: HTMLElement;
|
|
let buttonToggleLabelElement: HTMLLabelElement;
|
|
let buttonToggleInstance: MatButtonToggle;
|
|
let buttonToggleButtonElement: HTMLButtonElement;
|
|
|
|
beforeEach(fakeAsync(() => {
|
|
fixture = TestBed.createComponent(StandaloneButtonToggle);
|
|
fixture.detectChanges();
|
|
|
|
buttonToggleDebugElement = fixture.debugElement.query(By.directive(MatButtonToggle))!;
|
|
buttonToggleNativeElement = buttonToggleDebugElement.nativeElement;
|
|
buttonToggleLabelElement = fixture.debugElement.query(
|
|
By.css('.mat-button-toggle-label-content'),
|
|
)!.nativeElement;
|
|
buttonToggleInstance = buttonToggleDebugElement.componentInstance;
|
|
buttonToggleButtonElement = buttonToggleNativeElement.querySelector(
|
|
'button',
|
|
)! as HTMLButtonElement;
|
|
}));
|
|
|
|
it('should toggle when clicked', fakeAsync(() => {
|
|
buttonToggleLabelElement.click();
|
|
fixture.detectChanges();
|
|
flush();
|
|
|
|
expect(buttonToggleInstance.checked).toBe(true);
|
|
|
|
buttonToggleLabelElement.click();
|
|
fixture.detectChanges();
|
|
flush();
|
|
|
|
expect(buttonToggleInstance.checked).toBe(false);
|
|
}));
|
|
|
|
it('should emit a change event for state changes', fakeAsync(() => {
|
|
expect(buttonToggleInstance.checked).toBe(false);
|
|
|
|
const changeSpy = jasmine.createSpy('button-toggle change listener');
|
|
buttonToggleInstance.change.subscribe(changeSpy);
|
|
|
|
buttonToggleLabelElement.click();
|
|
fixture.detectChanges();
|
|
tick();
|
|
expect(changeSpy).toHaveBeenCalled();
|
|
|
|
buttonToggleLabelElement.click();
|
|
fixture.detectChanges();
|
|
tick();
|
|
|
|
// The default browser behavior is to emit an event, when the value was set
|
|
// to false. That's because the current input type is set to `checkbox`.
|
|
expect(changeSpy).toHaveBeenCalledTimes(2);
|
|
}));
|
|
|
|
it('should focus on underlying input element when focus() is called', () => {
|
|
const nativeButton = buttonToggleDebugElement.query(By.css('button'))!.nativeElement;
|
|
expect(document.activeElement).not.toBe(nativeButton);
|
|
|
|
buttonToggleInstance.focus();
|
|
fixture.detectChanges();
|
|
|
|
expect(document.activeElement).toBe(nativeButton);
|
|
});
|
|
|
|
it('should not assign a name to the underlying input if one is not passed in', () => {
|
|
expect(buttonToggleButtonElement.getAttribute('name')).toBeFalsy();
|
|
});
|
|
|
|
it('should have correct aria-pressed attribute', () => {
|
|
expect(buttonToggleButtonElement.getAttribute('aria-pressed')).toBe('false');
|
|
|
|
buttonToggleLabelElement.click();
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(buttonToggleButtonElement.getAttribute('aria-pressed')).toBe('true');
|
|
});
|
|
});
|
|
|
|
describe('aria-label handling ', () => {
|
|
it('should not set the aria-label attribute if none is provided', () => {
|
|
const fixture = TestBed.createComponent(StandaloneButtonToggle);
|
|
const checkboxDebugElement = fixture.debugElement.query(By.directive(MatButtonToggle))!;
|
|
const checkboxNativeElement = checkboxDebugElement.nativeElement;
|
|
const buttonElement = checkboxNativeElement.querySelector('button') as HTMLButtonElement;
|
|
|
|
fixture.detectChanges();
|
|
expect(buttonElement.hasAttribute('aria-label')).toBe(false);
|
|
});
|
|
|
|
it('should use the provided aria-label', () => {
|
|
const fixture = TestBed.createComponent(ButtonToggleWithAriaLabel);
|
|
const checkboxDebugElement = fixture.debugElement.query(By.directive(MatButtonToggle))!;
|
|
const checkboxNativeElement = checkboxDebugElement.nativeElement;
|
|
const buttonElement = checkboxNativeElement.querySelector('button') as HTMLButtonElement;
|
|
|
|
fixture.detectChanges();
|
|
expect(buttonElement.getAttribute('aria-label')).toBe('Super effective');
|
|
});
|
|
|
|
it('should clear the static aria from the host node', () => {
|
|
const fixture = TestBed.createComponent(ButtonToggleWithStaticAriaAttributes);
|
|
fixture.detectChanges();
|
|
const hostNode: HTMLElement = fixture.nativeElement.querySelector('mat-button-toggle');
|
|
|
|
expect(hostNode.hasAttribute('aria-label')).toBe(false);
|
|
expect(hostNode.hasAttribute('aria-labelledby')).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('with provided aria-labelledby ', () => {
|
|
let checkboxDebugElement: DebugElement;
|
|
let checkboxNativeElement: HTMLElement;
|
|
let buttonElement: HTMLButtonElement;
|
|
|
|
it('should use the provided aria-labelledby', () => {
|
|
const fixture = TestBed.createComponent(ButtonToggleWithAriaLabelledby);
|
|
checkboxDebugElement = fixture.debugElement.query(By.directive(MatButtonToggle))!;
|
|
checkboxNativeElement = checkboxDebugElement.nativeElement;
|
|
buttonElement = checkboxNativeElement.querySelector('button') as HTMLButtonElement;
|
|
|
|
fixture.detectChanges();
|
|
expect(buttonElement.getAttribute('aria-labelledby')).toBe('some-id');
|
|
});
|
|
|
|
it('should not assign aria-labelledby if none is provided', () => {
|
|
const fixture = TestBed.createComponent(StandaloneButtonToggle);
|
|
checkboxDebugElement = fixture.debugElement.query(By.directive(MatButtonToggle))!;
|
|
checkboxNativeElement = checkboxDebugElement.nativeElement;
|
|
buttonElement = checkboxNativeElement.querySelector('button') as HTMLButtonElement;
|
|
|
|
fixture.detectChanges();
|
|
expect(buttonElement.getAttribute('aria-labelledby')).toBe(null);
|
|
});
|
|
});
|
|
|
|
describe('with tabindex', () => {
|
|
it('should forward the tabindex to the underlying button', () => {
|
|
const fixture = TestBed.createComponent(ButtonToggleWithTabindex);
|
|
fixture.detectChanges();
|
|
|
|
const button = fixture.nativeElement.querySelector('.mat-button-toggle button');
|
|
|
|
expect(button.getAttribute('tabindex')).toBe('3');
|
|
});
|
|
|
|
it('should have role "presentation"', () => {
|
|
const fixture = TestBed.createComponent(ButtonToggleWithTabindex);
|
|
fixture.detectChanges();
|
|
|
|
const host = fixture.nativeElement.querySelector('.mat-button-toggle');
|
|
|
|
expect(host.getAttribute('role')).toBe('presentation');
|
|
});
|
|
|
|
it('should forward focus to the underlying button when the host is focused', () => {
|
|
const fixture = TestBed.createComponent(ButtonToggleWithTabindex);
|
|
fixture.detectChanges();
|
|
|
|
const host = fixture.nativeElement.querySelector('.mat-button-toggle');
|
|
const button = host.querySelector('button');
|
|
|
|
expect(document.activeElement).not.toBe(button);
|
|
|
|
host.focus();
|
|
|
|
expect(document.activeElement).toBe(button);
|
|
});
|
|
});
|
|
|
|
describe('with tokens to hide checkmark selection indicators', () => {
|
|
beforeEach(() => {
|
|
TestBed.configureTestingModule({
|
|
imports: [
|
|
MatButtonToggleModule,
|
|
ButtonTogglesInsideButtonToggleGroup,
|
|
ButtonTogglesInsideButtonToggleGroupMultiple,
|
|
],
|
|
providers: [
|
|
{
|
|
provide: MAT_BUTTON_TOGGLE_DEFAULT_OPTIONS,
|
|
useValue: {
|
|
hideSingleSelectionIndicator: true,
|
|
hideMultipleSelectionIndicator: true,
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('should hide checkmark indicator for single selection', () => {
|
|
const fixture = TestBed.createComponent(ButtonTogglesInsideButtonToggleGroup);
|
|
fixture.detectChanges();
|
|
|
|
fixture.debugElement.query(By.css('button')).nativeElement.click();
|
|
fixture.detectChanges();
|
|
|
|
expect(document.querySelectorAll('.mat-pseudo-checkbox').length).toBe(0);
|
|
});
|
|
|
|
it('should hide checkmark indicator for multiple selection', () => {
|
|
const fixture = TestBed.createComponent(ButtonTogglesInsideButtonToggleGroupMultiple);
|
|
fixture.detectChanges();
|
|
|
|
// Check all button toggles in the group
|
|
fixture.debugElement
|
|
.queryAll(By.css('button'))
|
|
.forEach(toggleButton => toggleButton.nativeElement.click());
|
|
fixture.detectChanges();
|
|
|
|
expect(document.querySelectorAll('.mat-pseudo-checkbox').length).toBe(0);
|
|
});
|
|
});
|
|
|
|
it('should not throw on init when toggles are repeated and there is an initial value', () => {
|
|
const fixture = TestBed.createComponent(RepeatedButtonTogglesWithPreselectedValue);
|
|
|
|
expect(() => fixture.detectChanges()).not.toThrow();
|
|
expect(fixture.componentInstance.toggleGroup.value).toBe('Two');
|
|
expect(fixture.componentInstance.toggles.toArray()[1].checked).toBe(true);
|
|
});
|
|
|
|
it('should not throw on init when toggles are repeated and there is an initial value', () => {
|
|
const fixture = TestBed.createComponent(ButtonToggleWithStaticName);
|
|
fixture.detectChanges();
|
|
|
|
const hostNode: HTMLElement = fixture.nativeElement.querySelector('.mat-button-toggle');
|
|
|
|
expect(hostNode.hasAttribute('name')).toBe(false);
|
|
expect(hostNode.querySelector('button')!.getAttribute('name')).toBe('custom-name');
|
|
});
|
|
|
|
it(
|
|
'should maintain the selected state when the value and toggles are swapped out at ' +
|
|
'the same time',
|
|
() => {
|
|
const fixture = TestBed.createComponent(RepeatedButtonTogglesWithPreselectedValue);
|
|
fixture.detectChanges();
|
|
|
|
expect(fixture.componentInstance.toggleGroup.value).toBe('Two');
|
|
expect(fixture.componentInstance.toggles.toArray()[1].checked).toBe(true);
|
|
|
|
fixture.componentInstance.possibleValues = ['Five', 'Six', 'Seven'];
|
|
fixture.componentInstance.value = 'Seven';
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(fixture.componentInstance.toggleGroup.value).toBe('Seven');
|
|
expect(fixture.componentInstance.toggles.toArray()[2].checked).toBe(true);
|
|
},
|
|
);
|
|
|
|
it('should select falsy button toggle value in multiple selection', () => {
|
|
const fixture = TestBed.createComponent(FalsyButtonTogglesInsideButtonToggleGroupMultiple);
|
|
fixture.detectChanges();
|
|
|
|
expect(fixture.componentInstance.toggles.toArray()[0].checked).toBe(true);
|
|
expect(fixture.componentInstance.toggles.toArray()[1].checked).toBe(false);
|
|
expect(fixture.componentInstance.toggles.toArray()[2].checked).toBe(false);
|
|
|
|
fixture.componentInstance.value = [0, false];
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(fixture.componentInstance.toggles.toArray()[0].checked).toBe(true);
|
|
expect(fixture.componentInstance.toggles.toArray()[1].checked).toBe(false);
|
|
expect(fixture.componentInstance.toggles.toArray()[2].checked).toBe(true);
|
|
});
|
|
|
|
it('should not throw if initial value is set during creation', () => {
|
|
const fixture = TestBed.createComponent(ButtonTogglesInsideButtonToggleGroupMultiple);
|
|
|
|
// In Ivy static inputs are set during creation. We simulate this by not calling
|
|
// `fixture.detectChanges` immediately, but getting a hold of the instance via the
|
|
// DebugElement and setting the value ourselves.
|
|
expect(() => {
|
|
const toggle = fixture.debugElement.query(By.css('mat-button-toggle'))!.componentInstance;
|
|
toggle.checked = true;
|
|
fixture.detectChanges();
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('should have a focus indicator', () => {
|
|
const fixture = TestBed.createComponent(ButtonTogglesInsideButtonToggleGroup);
|
|
const buttonNativeElements = [...fixture.debugElement.nativeElement.querySelectorAll('button')];
|
|
|
|
expect(
|
|
buttonNativeElements.every(element => element.classList.contains('mat-focus-indicator')),
|
|
).toBe(true);
|
|
});
|
|
|
|
it('should be able to pre-check a button toggle using a static checked binding', () => {
|
|
const fixture = TestBed.createComponent(ButtonToggleWithStaticChecked);
|
|
fixture.detectChanges();
|
|
|
|
expect(fixture.componentInstance.toggles.map(t => t.checked)).toEqual([false, true]);
|
|
expect(fixture.componentInstance.group.value).toBe('2');
|
|
});
|
|
});
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-button-toggle-group
|
|
[disabled]="isGroupDisabled"
|
|
[disabledInteractive]="disabledIntearctive"
|
|
[vertical]="isVertical"
|
|
[(value)]="groupValue">
|
|
@if (renderFirstToggle) {
|
|
<mat-button-toggle value="test1">Test1</mat-button-toggle>
|
|
}
|
|
<mat-button-toggle value="test2">Test2</mat-button-toggle>
|
|
<mat-button-toggle value="test3">Test3</mat-button-toggle>
|
|
</mat-button-toggle-group>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule],
|
|
})
|
|
class ButtonTogglesInsideButtonToggleGroup {
|
|
isGroupDisabled: boolean = false;
|
|
disabledIntearctive = false;
|
|
isVertical: boolean = false;
|
|
groupValue: string;
|
|
renderFirstToggle = true;
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-button-toggle-group
|
|
[name]="groupName"
|
|
[(ngModel)]="modelValue"
|
|
(change)="lastEvent = $event">
|
|
@for (option of options; track option) {
|
|
<mat-button-toggle
|
|
[value]="option.value"
|
|
[disableRipple]="disableRipple"
|
|
[name]="option.name">{{option.label}}</mat-button-toggle>
|
|
}
|
|
</mat-button-toggle-group>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule, FormsModule, ReactiveFormsModule],
|
|
})
|
|
class ButtonToggleGroupWithNgModel {
|
|
groupName = 'group-name';
|
|
modelValue: string;
|
|
options = [
|
|
{label: 'Red', value: 'red', name: ''},
|
|
{label: 'Green', value: 'green', name: ''},
|
|
{label: 'Blue', value: 'blue', name: ''},
|
|
];
|
|
lastEvent: MatButtonToggleChange;
|
|
disableRipple = false;
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-button-toggle-group [disabled]="isGroupDisabled" [vertical]="isVertical" multiple>
|
|
<mat-button-toggle value="eggs">Eggs</mat-button-toggle>
|
|
<mat-button-toggle value="flour">Flour</mat-button-toggle>
|
|
<mat-button-toggle value="sugar">Sugar</mat-button-toggle>
|
|
</mat-button-toggle-group>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule],
|
|
})
|
|
class ButtonTogglesInsideButtonToggleGroupMultiple {
|
|
isGroupDisabled: boolean = false;
|
|
isVertical: boolean = false;
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-button-toggle-group multiple [value]="value">
|
|
<mat-button-toggle [value]="0">Eggs</mat-button-toggle>
|
|
<mat-button-toggle [value]="null">Flour</mat-button-toggle>
|
|
<mat-button-toggle [value]="false">Sugar</mat-button-toggle>
|
|
<mat-button-toggle>Sugar</mat-button-toggle>
|
|
</mat-button-toggle-group>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule],
|
|
})
|
|
class FalsyButtonTogglesInsideButtonToggleGroupMultiple {
|
|
value: ('' | number | null | undefined | boolean)[] = [0];
|
|
@ViewChildren(MatButtonToggle) toggles: QueryList<MatButtonToggle>;
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-button-toggle>Yes</mat-button-toggle>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule],
|
|
})
|
|
class StandaloneButtonToggle {}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-button-toggle-group (change)="lastEvent = $event" value="red">
|
|
<mat-button-toggle value="red">Value Red</mat-button-toggle>
|
|
<mat-button-toggle value="green">Value Green</mat-button-toggle>
|
|
</mat-button-toggle-group>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule],
|
|
})
|
|
class ButtonToggleGroupWithInitialValue {
|
|
lastEvent: MatButtonToggleChange;
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-button-toggle-group [formControl]="control">
|
|
<mat-button-toggle value="red">Value Red</mat-button-toggle>
|
|
<mat-button-toggle value="green">Value Green</mat-button-toggle>
|
|
<mat-button-toggle value="blue">Value Blue</mat-button-toggle>
|
|
</mat-button-toggle-group>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule, FormsModule, ReactiveFormsModule],
|
|
})
|
|
class ButtonToggleGroupWithFormControl {
|
|
control = new FormControl('');
|
|
}
|
|
|
|
@Component({
|
|
// We need the `@if` so that there's a container between the group and the toggles.
|
|
template: `
|
|
<mat-button-toggle-group [formControl]="control">
|
|
@if (true) {
|
|
<mat-button-toggle value="red">Value Red</mat-button-toggle>
|
|
<mat-button-toggle value="green">Value Green</mat-button-toggle>
|
|
<mat-button-toggle value="blue">Value Blue</mat-button-toggle>
|
|
}
|
|
</mat-button-toggle-group>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule, FormsModule, ReactiveFormsModule],
|
|
})
|
|
class ButtonToggleGroupWithIndirectDescendantToggles {
|
|
control = new FormControl('');
|
|
}
|
|
|
|
/** Simple test component with an aria-label set. */
|
|
@Component({
|
|
template: `<mat-button-toggle aria-label="Super effective"></mat-button-toggle>`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule],
|
|
})
|
|
class ButtonToggleWithAriaLabel {}
|
|
|
|
/** Simple test component with an aria-label set. */
|
|
@Component({
|
|
template: `<mat-button-toggle aria-labelledby="some-id"></mat-button-toggle>`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule],
|
|
})
|
|
class ButtonToggleWithAriaLabelledby {}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-button-toggle-group [(value)]="value">
|
|
@for (toggle of possibleValues; track toggle) {
|
|
<mat-button-toggle [value]="toggle">{{toggle}}</mat-button-toggle>
|
|
}
|
|
</mat-button-toggle-group>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule],
|
|
})
|
|
class RepeatedButtonTogglesWithPreselectedValue {
|
|
@ViewChild(MatButtonToggleGroup) toggleGroup: MatButtonToggleGroup;
|
|
@ViewChildren(MatButtonToggle) toggles: QueryList<MatButtonToggle>;
|
|
|
|
possibleValues = ['One', 'Two', 'Three'];
|
|
value = 'Two';
|
|
}
|
|
|
|
@Component({
|
|
template: `<mat-button-toggle tabindex="3"></mat-button-toggle>`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule],
|
|
})
|
|
class ButtonToggleWithTabindex {}
|
|
|
|
@Component({
|
|
template: `<mat-button-toggle name="custom-name"></mat-button-toggle>`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule],
|
|
})
|
|
class ButtonToggleWithStaticName {}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-button-toggle-group>
|
|
<mat-button-toggle value="1">One</mat-button-toggle>
|
|
<mat-button-toggle value="2" checked>Two</mat-button-toggle>
|
|
</mat-button-toggle-group>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule],
|
|
})
|
|
class ButtonToggleWithStaticChecked {
|
|
@ViewChild(MatButtonToggleGroup) group: MatButtonToggleGroup;
|
|
@ViewChildren(MatButtonToggle) toggles: QueryList<MatButtonToggle>;
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-button-toggle aria-label="Toggle me" aria-labelledby="something"></mat-button-toggle>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule],
|
|
})
|
|
class ButtonToggleWithStaticAriaAttributes {}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-button-toggle-group [formControl]="control">
|
|
@for (value of values; track value) {
|
|
<mat-button-toggle [value]="value">{{value}}</mat-button-toggle>
|
|
}
|
|
</mat-button-toggle-group>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule, FormsModule, ReactiveFormsModule],
|
|
})
|
|
class ButtonToggleGroupWithFormControlAndDynamicButtons {
|
|
@ViewChildren(MatButtonToggle) toggles: QueryList<MatButtonToggle>;
|
|
control = new FormControl('');
|
|
values = ['a', 'b', 'c'];
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-button-toggle-group [(ngModel)]="value">
|
|
<mat-button-toggle value="1">One</mat-button-toggle>
|
|
<mat-button-toggle value="2">Two</mat-button-toggle>
|
|
<mat-button-toggle value="3">Three</mat-button-toggle>
|
|
</mat-button-toggle-group>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatButtonToggleModule, FormsModule],
|
|
})
|
|
class ButtonToggleGroupWithNgModelAndStaticOptions {
|
|
value = '';
|
|
}
|