Skip to content

Commit 37b20e7

Browse files
committed
Adds injectable provider config to set the default color and click action.
Follow-up PR will add the same default options to the MDC component. BREAKING CHANGE: MAT_CHECKBOX_CLICK_ACTION is deprecated, use MAT_CHECKBOX_DEFAULT_OPTIONS
1 parent 1ad9ef0 commit 37b20e7

File tree

5 files changed

+152
-10
lines changed

5 files changed

+152
-10
lines changed

src/material/checkbox/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ ng_test_library(
6161
":checkbox",
6262
"//src/cdk/observers",
6363
"//src/cdk/testing/private",
64+
"//src/material/core",
6465
"@npm//@angular/forms",
6566
"@npm//@angular/platform-browser",
6667
],

src/material/checkbox/checkbox-config.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,28 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import {InjectionToken} from '@angular/core';
9+
import {ThemePalette} from '@angular/material/core';
910

11+
/** Default `mat-checkbox` options that can be overridden. */
12+
export interface MatCheckboxDefaultOptions {
13+
color?: ThemePalette;
14+
clickAction?: MatCheckboxClickAction;
15+
}
16+
17+
/** Injection token to be used to override the default options for `mat-checkbox`. */
18+
export const MAT_CHECKBOX_DEFAULT_OPTIONS =
19+
new InjectionToken<MatCheckboxDefaultOptions>('mat-checkbox-default-options', {
20+
providedIn: 'root',
21+
factory: MAT_CHECKBOX_DEFAULT_OPTIONS_FACTORY
22+
});
23+
24+
/** @docs-private */
25+
export function MAT_CHECKBOX_DEFAULT_OPTIONS_FACTORY(): MatCheckboxDefaultOptions {
26+
return {
27+
color: 'accent',
28+
clickAction: 'check-indeterminate',
29+
};
30+
}
1031

1132
/**
1233
* Checkbox click action when user click on input element.
@@ -19,6 +40,8 @@ export type MatCheckboxClickAction = 'noop' | 'check' | 'check-indeterminate' |
1940

2041
/**
2142
* Injection token that can be used to specify the checkbox click behavior.
43+
* @deprecated Injection token will be removed, use `MAT_CHECKBOX_DEFAULT_OPTIONS` instead.
44+
* @breaking-change 10.0.0
2245
*/
2346
export const MAT_CHECKBOX_CLICK_ACTION =
2447
new InjectionToken<MatCheckboxClickAction>('mat-checkbox-click-action');

src/material/checkbox/checkbox.spec.ts

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@ import {FormControl, FormsModule, NgModel, ReactiveFormsModule} from '@angular/f
99
import {Component, DebugElement, ViewChild, Type, ChangeDetectionStrategy} from '@angular/core';
1010
import {By} from '@angular/platform-browser';
1111
import {dispatchFakeEvent} from '@angular/cdk/testing/private';
12-
import {MatCheckbox, MatCheckboxChange, MatCheckboxModule} from './index';
12+
import {
13+
MAT_CHECKBOX_DEFAULT_OPTIONS,
14+
MatCheckbox,
15+
MatCheckboxChange,
16+
MatCheckboxModule
17+
} from './index';
1318
import {MAT_CHECKBOX_CLICK_ACTION} from './checkbox-config';
1419
import {MutationObserverFactory} from '@angular/cdk/observers';
20+
import {ThemePalette} from '@angular/material/core';
1521

1622

1723
describe('MatCheckbox', () => {
@@ -533,14 +539,47 @@ describe('MatCheckbox', () => {
533539
}));
534540
});
535541

542+
describe(`when MAT_CHECKBOX_CLICK_ACTION is set`, () => {
543+
beforeEach(() => {
544+
TestBed.resetTestingModule();
545+
TestBed.configureTestingModule({
546+
imports: [MatCheckboxModule, FormsModule, ReactiveFormsModule],
547+
declarations: [SingleCheckbox],
548+
providers: [
549+
{provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'check'},
550+
{provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: {clickAction: 'noop'}}
551+
]
552+
});
553+
554+
fixture = createComponent(SingleCheckbox);
555+
fixture.detectChanges();
556+
557+
checkboxDebugElement = fixture.debugElement.query(By.directive(MatCheckbox))!;
558+
checkboxNativeElement = checkboxDebugElement.nativeElement;
559+
testComponent = fixture.debugElement.componentInstance;
560+
561+
inputElement = checkboxNativeElement.querySelector('input') as HTMLInputElement;
562+
});
563+
564+
it('should override the value set in the default options', fakeAsync(() => {
565+
testComponent.isIndeterminate = true;
566+
inputElement.click();
567+
fixture.detectChanges();
568+
flush();
569+
570+
expect(inputElement.checked).toBe(true);
571+
expect(inputElement.indeterminate).toBe(true);
572+
}));
573+
});
574+
536575
describe(`when MAT_CHECKBOX_CLICK_ACTION is 'check'`, () => {
537576
beforeEach(() => {
538577
TestBed.resetTestingModule();
539578
TestBed.configureTestingModule({
540579
imports: [MatCheckboxModule, FormsModule, ReactiveFormsModule],
541580
declarations: [SingleCheckbox],
542581
providers: [
543-
{provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'check'}
582+
{provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: {clickAction: 'check'}}
544583
]
545584
});
546585

@@ -577,7 +616,7 @@ describe('MatCheckbox', () => {
577616
imports: [MatCheckboxModule, FormsModule, ReactiveFormsModule],
578617
declarations: [SingleCheckbox],
579618
providers: [
580-
{provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop'}
619+
{provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: {clickAction: 'noop'}}
581620
]
582621
});
583622

@@ -1155,6 +1194,50 @@ describe('MatCheckbox', () => {
11551194
});
11561195
});
11571196

1197+
describe('MatCheckboxDefaultOptions', () => {
1198+
describe('when MAT_CHECKBOX_DEFAULT_OPTIONS overridden', () => {
1199+
beforeEach(() => {
1200+
TestBed.configureTestingModule({
1201+
imports: [MatCheckboxModule, FormsModule],
1202+
declarations: [SingleCheckbox, SimpleCheckbox],
1203+
providers: [{
1204+
provide: MAT_CHECKBOX_DEFAULT_OPTIONS,
1205+
useValue: {color: 'primary'},
1206+
}],
1207+
});
1208+
1209+
TestBed.compileComponents();
1210+
});
1211+
1212+
it('should override default color in Component', () => {
1213+
const fixture: ComponentFixture<SimpleCheckbox> =
1214+
TestBed.createComponent(SimpleCheckbox);
1215+
fixture.detectChanges();
1216+
const checkboxDebugElement: DebugElement =
1217+
fixture.debugElement.query(By.directive(MatCheckbox))!;
1218+
expect(
1219+
checkboxDebugElement.nativeElement.classList
1220+
).toContain('mat-primary');
1221+
});
1222+
1223+
it('should not override explicit input bindings', () => {
1224+
const fixture: ComponentFixture<SingleCheckbox> =
1225+
TestBed.createComponent(SingleCheckbox);
1226+
fixture.componentInstance.checkboxColor = 'warn';
1227+
fixture.detectChanges();
1228+
const checkboxDebugElement: DebugElement =
1229+
fixture.debugElement.query(By.directive(MatCheckbox))!;
1230+
expect(
1231+
checkboxDebugElement.nativeElement.classList
1232+
).not.toContain('mat-primary');
1233+
expect(
1234+
checkboxDebugElement.nativeElement.classList
1235+
).toContain('mat-warn');
1236+
expect(checkboxDebugElement.nativeElement.classList).toContain('mat-warn');
1237+
});
1238+
});
1239+
});
1240+
11581241
/** Simple component for testing a single checkbox. */
11591242
@Component({
11601243
template: `
@@ -1185,7 +1268,7 @@ class SingleCheckbox {
11851268
parentElementClicked: boolean = false;
11861269
parentElementKeyedUp: boolean = false;
11871270
checkboxId: string | null = 'simple-check';
1188-
checkboxColor: string = 'primary';
1271+
checkboxColor: ThemePalette = 'primary';
11891272
checkboxValue: string = 'single_checkbox';
11901273

11911274
onCheckboxClick: (event?: Event) => void = () => {};
@@ -1306,3 +1389,8 @@ class CheckboxWithProjectedLabel {}
13061389
class TextBindingComponent {
13071390
text: string = 'Some text';
13081391
}
1392+
1393+
/** Test component with a simple checkbox with no inputs. */
1394+
@Component({template: `<mat-checkbox></mat-checkbox>`})
1395+
class SimpleCheckbox {
1396+
}

src/material/checkbox/checkbox.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {FocusMonitor, FocusableOption, FocusOrigin} from '@angular/cdk/a11y';
9+
import {FocusableOption, FocusMonitor, FocusOrigin} from '@angular/cdk/a11y';
1010
import {coerceBooleanProperty} from '@angular/cdk/coercion';
1111
import {
12+
AfterViewChecked,
1213
Attribute,
1314
ChangeDetectionStrategy,
1415
ChangeDetectorRef,
@@ -24,7 +25,6 @@ import {
2425
Output,
2526
ViewChild,
2627
ViewEncapsulation,
27-
AfterViewChecked,
2828
} from '@angular/core';
2929
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
3030
import {
@@ -43,7 +43,12 @@ import {
4343
mixinTabIndex,
4444
} from '@angular/material/core';
4545
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
46-
import {MAT_CHECKBOX_CLICK_ACTION, MatCheckboxClickAction} from './checkbox-config';
46+
import {
47+
MAT_CHECKBOX_CLICK_ACTION,
48+
MAT_CHECKBOX_DEFAULT_OPTIONS,
49+
MatCheckboxClickAction,
50+
MatCheckboxDefaultOptions
51+
} from './checkbox-config';
4752

4853

4954
// Increasing integer for generating unique ids for checkbox components.
@@ -94,7 +99,7 @@ const _MatCheckboxMixinBase:
9499
CanDisableRippleCtor &
95100
CanDisableCtor &
96101
typeof MatCheckboxBase =
97-
mixinTabIndex(mixinColor(mixinDisableRipple(mixinDisabled(MatCheckboxBase)), 'accent'));
102+
mixinTabIndex(mixinColor(mixinDisableRipple(mixinDisabled(MatCheckboxBase))));
98103

99104

100105
/**
@@ -194,10 +199,22 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc
194199
private _focusMonitor: FocusMonitor,
195200
private _ngZone: NgZone,
196201
@Attribute('tabindex') tabIndex: string,
202+
/**
203+
* @deprecated `_clickAction` parameter to be removed, use
204+
* `MAT_CHECKBOX_DEFAULT_OPTIONS`
205+
* @breaking-change 10.0.0
206+
*/
197207
@Optional() @Inject(MAT_CHECKBOX_CLICK_ACTION)
198208
private _clickAction: MatCheckboxClickAction,
199-
@Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode?: string) {
209+
@Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode?: string,
210+
@Optional() @Inject(MAT_CHECKBOX_DEFAULT_OPTIONS)
211+
private _options?: MatCheckboxDefaultOptions) {
200212
super(elementRef);
213+
this._options = this._options || {};
214+
215+
if (this._options.color) {
216+
this.color = this._options.color;
217+
}
201218

202219
this.tabIndex = parseInt(tabIndex) || 0;
203220

@@ -214,6 +231,9 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc
214231
});
215232
}
216233
});
234+
235+
// TODO: Remove this after the `_clickAction` parameter is removed as an injection parameter.
236+
this._clickAction = this._clickAction || this._options.clickAction;
217237
}
218238

219239
// TODO: Delete next major revision.

tools/public_api_guard/material/checkbox.d.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ export declare const MAT_CHECKBOX_CLICK_ACTION: InjectionToken<MatCheckboxClickA
55

66
export declare const MAT_CHECKBOX_CONTROL_VALUE_ACCESSOR: any;
77

8+
export declare const MAT_CHECKBOX_DEFAULT_OPTIONS: InjectionToken<MatCheckboxDefaultOptions>;
9+
10+
export declare function MAT_CHECKBOX_DEFAULT_OPTIONS_FACTORY(): MatCheckboxDefaultOptions;
11+
812
export declare const MAT_CHECKBOX_REQUIRED_VALIDATOR: Provider;
913

1014
export declare class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAccessor, AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple, FocusableOption {
@@ -25,7 +29,8 @@ export declare class MatCheckbox extends _MatCheckboxMixinBase implements Contro
2529
required: boolean;
2630
ripple: MatRipple;
2731
value: string;
28-
constructor(elementRef: ElementRef<HTMLElement>, _changeDetectorRef: ChangeDetectorRef, _focusMonitor: FocusMonitor, _ngZone: NgZone, tabIndex: string, _clickAction: MatCheckboxClickAction, _animationMode?: string | undefined);
32+
constructor(elementRef: ElementRef<HTMLElement>, _changeDetectorRef: ChangeDetectorRef, _focusMonitor: FocusMonitor, _ngZone: NgZone, tabIndex: string,
33+
_clickAction: MatCheckboxClickAction, _animationMode?: string | undefined, _options?: MatCheckboxDefaultOptions | undefined);
2934
_getAriaChecked(): 'true' | 'false' | 'mixed';
3035
_isRippleDisabled(): any;
3136
_onInputClick(event: Event): void;
@@ -48,6 +53,11 @@ export declare class MatCheckboxChange {
4853

4954
export declare type MatCheckboxClickAction = 'noop' | 'check' | 'check-indeterminate' | undefined;
5055

56+
export interface MatCheckboxDefaultOptions {
57+
clickAction?: MatCheckboxClickAction;
58+
color?: ThemePalette;
59+
}
60+
5161
export declare class MatCheckboxModule {
5262
}
5363

0 commit comments

Comments
 (0)