diff --git a/src/material-experimental/mdc-checkbox/checkbox.html b/src/material-experimental/mdc-checkbox/checkbox.html index 7d7cf5dd95db..28f63297fa18 100644 --- a/src/material-experimental/mdc-checkbox/checkbox.html +++ b/src/material-experimental/mdc-checkbox/checkbox.html @@ -11,7 +11,6 @@ [attr.value]="value" [checked]="checked" [disabled]="disabled" - [indeterminate]="indeterminate" [id]="inputId" [required]="required" [tabIndex]="tabIndex" diff --git a/src/material-experimental/mdc-checkbox/checkbox.ts b/src/material-experimental/mdc-checkbox/checkbox.ts index 48247035cba8..bb54f7fe3349 100644 --- a/src/material-experimental/mdc-checkbox/checkbox.ts +++ b/src/material-experimental/mdc-checkbox/checkbox.ts @@ -123,6 +123,7 @@ export class MatCheckbox implements AfterViewInit, OnDestroy, ControlValueAccess } set indeterminate(indeterminate) { this._indeterminate = coerceBooleanProperty(indeterminate); + this._syncIndeterminate(this._indeterminate); } private _indeterminate = false; @@ -257,6 +258,7 @@ export class MatCheckbox implements AfterViewInit, OnDestroy, ControlValueAccess } ngAfterViewInit() { + this._syncIndeterminate(this._indeterminate); this._checkboxFoundation.init(); } @@ -370,6 +372,21 @@ export class MatCheckbox implements AfterViewInit, OnDestroy, ControlValueAccess this._changeDetectorRef.markForCheck(); } + /** + * Syncs the indeterminate value with the checkbox DOM node. + * + * We sync `indeterminate` directly on the DOM node, because in Ivy the check for whether a + * property is supported on an element boils down to `if (propName in element)`. Domino's + * HTMLInputElement doesn't have an `indeterminate` property so Ivy will warn during + * server-side rendering. + */ + private _syncIndeterminate(value: boolean) { + const nativeCheckbox = this._nativeCheckbox; + if (nativeCheckbox) { + nativeCheckbox.nativeElement.indeterminate = value; + } + } + static ngAcceptInputType_checked: boolean | string | null | undefined; static ngAcceptInputType_indeterminate: boolean | string | null | undefined; static ngAcceptInputType_disabled: boolean | string | null | undefined; diff --git a/src/material/checkbox/checkbox.html b/src/material/checkbox/checkbox.html index 0c23dae408e6..80a74d8e73d6 100644 --- a/src/material/checkbox/checkbox.html +++ b/src/material/checkbox/checkbox.html @@ -10,7 +10,6 @@ [disabled]="disabled" [attr.name]="name" [tabIndex]="tabIndex" - [indeterminate]="indeterminate" [attr.aria-label]="ariaLabel || null" [attr.aria-labelledby]="ariaLabelledby" [attr.aria-checked]="_getAriaChecked()" diff --git a/src/material/checkbox/checkbox.ts b/src/material/checkbox/checkbox.ts index b559cf264b64..c499d9c46565 100644 --- a/src/material/checkbox/checkbox.ts +++ b/src/material/checkbox/checkbox.ts @@ -25,6 +25,7 @@ import { Output, ViewChild, ViewEncapsulation, + AfterViewInit, } from '@angular/core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; import { @@ -131,7 +132,7 @@ const _MatCheckboxMixinBase: changeDetection: ChangeDetectionStrategy.OnPush }) export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAccessor, - AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple, + AfterViewInit, AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple, FocusableOption { /** @@ -235,6 +236,10 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc this._clickAction = this._clickAction || this._options.clickAction; } + ngAfterViewInit() { + this._syncIndeterminate(this._indeterminate); + } + // TODO: Delete next major revision. ngAfterViewChecked() {} @@ -281,7 +286,7 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc get indeterminate(): boolean { return this._indeterminate; } set indeterminate(value: boolean) { const changed = value != this._indeterminate; - this._indeterminate = value; + this._indeterminate = coerceBooleanProperty(value); if (changed) { if (this._indeterminate) { @@ -292,6 +297,8 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc } this.indeterminateChange.emit(this._indeterminate); } + + this._syncIndeterminate(this._indeterminate); } private _indeterminate: boolean = false; @@ -470,7 +477,24 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc return `mat-checkbox-anim-${animSuffix}`; } + /** + * Syncs the indeterminate value with the checkbox DOM node. + * + * We sync `indeterminate` directly on the DOM node, because in Ivy the check for whether a + * property is supported on an element boils down to `if (propName in element)`. Domino's + * HTMLInputElement doesn't have an `indeterminate` property so Ivy will warn during + * server-side rendering. + */ + private _syncIndeterminate(value: boolean) { + const nativeCheckbox = this._inputElement; + + if (nativeCheckbox) { + nativeCheckbox.nativeElement.indeterminate = value; + } + } + static ngAcceptInputType_disabled: boolean | string | null | undefined; static ngAcceptInputType_required: boolean | string | null | undefined; static ngAcceptInputType_disableRipple: boolean | string | null | undefined; + static ngAcceptInputType_indeterminate: boolean | string | null | undefined; } diff --git a/tools/public_api_guard/material/checkbox.d.ts b/tools/public_api_guard/material/checkbox.d.ts index e3934b82c14d..29028ea699ff 100644 --- a/tools/public_api_guard/material/checkbox.d.ts +++ b/tools/public_api_guard/material/checkbox.d.ts @@ -13,7 +13,7 @@ export declare function MAT_CHECKBOX_DEFAULT_OPTIONS_FACTORY(): MatCheckboxDefau export declare const MAT_CHECKBOX_REQUIRED_VALIDATOR: Provider; -export declare class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAccessor, AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple, FocusableOption { +export declare class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAccessor, AfterViewInit, AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple, FocusableOption { _animationMode?: string | undefined; _inputElement: ElementRef; _onTouched: () => any; @@ -40,6 +40,7 @@ export declare class MatCheckbox extends _MatCheckboxMixinBase implements Contro _onLabelTextChange(): void; focus(origin?: FocusOrigin, options?: FocusOptions): void; ngAfterViewChecked(): void; + ngAfterViewInit(): void; ngOnDestroy(): void; registerOnChange(fn: (value: any) => void): void; registerOnTouched(fn: any): void; @@ -48,6 +49,7 @@ export declare class MatCheckbox extends _MatCheckboxMixinBase implements Contro writeValue(value: any): void; static ngAcceptInputType_disableRipple: boolean | string | null | undefined; static ngAcceptInputType_disabled: boolean | string | null | undefined; + static ngAcceptInputType_indeterminate: boolean | string | null | undefined; static ngAcceptInputType_required: boolean | string | null | undefined; static ɵcmp: i0.ɵɵComponentDefWithMeta; static ɵfac: i0.ɵɵFactoryDef;