From 4cc69d249e11527816d4272daf98552b35a5bd42 Mon Sep 17 00:00:00 2001 From: Andrew Seguin Date: Mon, 4 Nov 2019 15:38:51 -0800 Subject: [PATCH] feat(material-experimental/mdc-checkbox): add default options (#17578) * feat(material-experimental/mdc-checkbox): add default options * add breaking changes comment --- .../mdc-checkbox/checkbox.spec.ts | 86 ++++++++++++++++++- .../mdc-checkbox/checkbox.ts | 29 ++++++- 2 files changed, 109 insertions(+), 6 deletions(-) diff --git a/src/material-experimental/mdc-checkbox/checkbox.spec.ts b/src/material-experimental/mdc-checkbox/checkbox.spec.ts index 558da386c0a2..08c8e6a7ba9a 100644 --- a/src/material-experimental/mdc-checkbox/checkbox.spec.ts +++ b/src/material-experimental/mdc-checkbox/checkbox.spec.ts @@ -15,6 +15,7 @@ import { MatCheckboxChange, MatCheckboxModule } from './index'; +import {MAT_CHECKBOX_DEFAULT_OPTIONS} from '@angular/material/checkbox'; describe('MatCheckbox', () => { @@ -468,13 +469,48 @@ describe('MatCheckbox', () => { })); }); + describe(`when MAT_CHECKBOX_CLICK_ACTION is set`, () => { + beforeEach(() => { + TestBed.resetTestingModule(); + TestBed.configureTestingModule({ + imports: [MatCheckboxModule, FormsModule, ReactiveFormsModule], + declarations: [SingleCheckbox], + providers: [ + {provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'check'}, + {provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: {clickAction: 'noop'}} + ] + }); + + fixture = createComponent(SingleCheckbox); + fixture.detectChanges(); + + checkboxDebugElement = fixture.debugElement.query(By.directive(MatCheckbox))!; + checkboxNativeElement = checkboxDebugElement.nativeElement; + testComponent = fixture.debugElement.componentInstance; + + inputElement = checkboxNativeElement.querySelector('input') as HTMLInputElement; + }); + + it('should override the value set in the default options', fakeAsync(() => { + testComponent.isIndeterminate = true; + inputElement.click(); + fixture.detectChanges(); + flush(); + + expect(inputElement.checked).toBe(true); + expect(inputElement.indeterminate).toBe(true); + })); + }); + describe(`when MAT_CHECKBOX_CLICK_ACTION is 'check'`, () => { beforeEach(() => { TestBed.resetTestingModule(); TestBed.configureTestingModule({ imports: [MatCheckboxModule, FormsModule, ReactiveFormsModule], declarations: [SingleCheckbox], - providers: [{provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'check'}] + providers: [ + {provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: {clickAction: 'check'}} + ] }); fixture = createComponent(SingleCheckbox); @@ -506,7 +542,9 @@ describe('MatCheckbox', () => { TestBed.configureTestingModule({ imports: [MatCheckboxModule, FormsModule, ReactiveFormsModule], declarations: [SingleCheckbox], - providers: [{provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop'}] + providers: [ + {provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: {clickAction: 'noop'}} + ] }); fixture = createComponent(SingleCheckbox); @@ -933,6 +971,50 @@ describe('MatCheckbox', () => { }); }); +describe('MatCheckboxDefaultOptions', () => { + describe('when MAT_CHECKBOX_DEFAULT_OPTIONS overridden', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [MatCheckboxModule, FormsModule], + declarations: [SingleCheckbox, SingleCheckbox], + providers: [{ + provide: MAT_CHECKBOX_DEFAULT_OPTIONS, + useValue: {color: 'primary'}, + }], + }); + + TestBed.compileComponents(); + }); + + it('should override default color in component', () => { + const fixture: ComponentFixture = + TestBed.createComponent(SingleCheckbox); + fixture.detectChanges(); + const checkboxDebugElement: DebugElement = + fixture.debugElement.query(By.directive(MatCheckbox))!; + expect( + checkboxDebugElement.nativeElement.classList + ).toContain('mat-primary'); + }); + + it('should not override explicit input bindings', () => { + const fixture: ComponentFixture = + TestBed.createComponent(SingleCheckbox); + fixture.componentInstance.checkboxColor = 'warn'; + fixture.detectChanges(); + const checkboxDebugElement: DebugElement = + fixture.debugElement.query(By.directive(MatCheckbox))!; + expect( + checkboxDebugElement.nativeElement.classList + ).not.toContain('mat-primary'); + expect( + checkboxDebugElement.nativeElement.classList + ).toContain('mat-warn'); + expect(checkboxDebugElement.nativeElement.classList).toContain('mat-warn'); + }); + }); +}); + /** Simple component for testing a single checkbox. */ @Component({ template: ` diff --git a/src/material-experimental/mdc-checkbox/checkbox.ts b/src/material-experimental/mdc-checkbox/checkbox.ts index 345524bb1be2..648784b0fee8 100644 --- a/src/material-experimental/mdc-checkbox/checkbox.ts +++ b/src/material-experimental/mdc-checkbox/checkbox.ts @@ -26,7 +26,11 @@ import { ViewEncapsulation } from '@angular/core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; -import {MAT_CHECKBOX_CLICK_ACTION, MatCheckboxClickAction} from '@angular/material/checkbox'; +import { + MAT_CHECKBOX_CLICK_ACTION, + MAT_CHECKBOX_DEFAULT_OPTIONS, + MatCheckboxClickAction, MatCheckboxDefaultOptions +} from '@angular/material/checkbox'; import {ThemePalette} from '@angular/material/core'; import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; import {MDCCheckboxAdapter, MDCCheckboxFoundation} from '@material/checkbox'; @@ -228,12 +232,29 @@ export class MatCheckbox implements AfterViewInit, OnDestroy, ControlValueAccess private _changeDetectorRef: ChangeDetectorRef, private _platform: Platform, @Attribute('tabindex') tabIndex: string, + /** + * @deprecated `_clickAction` parameter to be removed, use + * `MAT_CHECKBOX_DEFAULT_OPTIONS` + * @breaking-change 10.0.0 + */ @Optional() @Inject(MAT_CHECKBOX_CLICK_ACTION) private _clickAction: MatCheckboxClickAction, - @Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode?: string) { - this.tabIndex = parseInt(tabIndex) || 0; - this._checkboxFoundation = new MDCCheckboxFoundation(this._checkboxAdapter); + @Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode?: string, + @Optional() @Inject(MAT_CHECKBOX_DEFAULT_OPTIONS) + private _options?: MatCheckboxDefaultOptions) { // Note: We don't need to set up the MDCFormFieldFoundation. Its only purpose is to manage the // ripple, which we do ourselves instead. + this.tabIndex = parseInt(tabIndex) || 0; + this._checkboxFoundation = new MDCCheckboxFoundation(this._checkboxAdapter); + + this._options = this._options || {}; + + if (this._options.color) { + this.color = this._options.color; + } + + // @breaking-change 10.0.0: Remove this after the `_clickAction` parameter is removed as an + // injection parameter. + this._clickAction = this._clickAction || this._options.clickAction; } ngAfterViewInit() {