Skip to content

Commit 8c75a17

Browse files
committed
fix(checkbox): unknown property warning with Ivy during server-side rendering
Ivy's check for whether a property supported is basically `if (propName in element)` which logs a warning if it doesn't match. It seems like Domino hasn't implemented the `indeterminate` property for `input` so Angular ends up logging a warning during server-side rendering. These changes switch to setting the property directly to avoid using a property binding. Also fixes that the current Material checkbox wasn't coercing the `indeterminate` input to a boolean.
1 parent 69ccd34 commit 8c75a17

File tree

5 files changed

+44
-5
lines changed

5 files changed

+44
-5
lines changed

src/material-experimental/mdc-checkbox/checkbox.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
[attr.value]="value"
1212
[checked]="checked"
1313
[disabled]="disabled"
14-
[indeterminate]="indeterminate"
1514
[id]="inputId"
1615
[required]="required"
1716
[tabIndex]="tabIndex"

src/material-experimental/mdc-checkbox/checkbox.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export class MatCheckbox implements AfterViewInit, OnDestroy, ControlValueAccess
124124
}
125125
set indeterminate(indeterminate) {
126126
this._indeterminate = coerceBooleanProperty(indeterminate);
127+
this._syncIndeterminate(this._indeterminate);
127128
}
128129
private _indeterminate = false;
129130

@@ -258,6 +259,7 @@ export class MatCheckbox implements AfterViewInit, OnDestroy, ControlValueAccess
258259
}
259260

260261
ngAfterViewInit() {
262+
this._syncIndeterminate(this._indeterminate);
261263
this._checkboxFoundation.init();
262264
}
263265

@@ -371,6 +373,21 @@ export class MatCheckbox implements AfterViewInit, OnDestroy, ControlValueAccess
371373
this._changeDetectorRef.markForCheck();
372374
}
373375

376+
/**
377+
* Syncs the indeterminate value with the checkbox DOM node.
378+
*
379+
* We sync `indeterminate` directly on the DOM node, because in Ivy the check for whether a
380+
* property is supported on an element boils down to `if (propName in element)`. Domino's
381+
* HTMLInputElement doesn't have an `indeterminate` property so Ivy will warn during
382+
* server-side rendering.
383+
*/
384+
private _syncIndeterminate(value: boolean) {
385+
const nativeCheckbox = this._nativeCheckbox;
386+
if (nativeCheckbox) {
387+
nativeCheckbox.nativeElement.indeterminate = value;
388+
}
389+
}
390+
374391
static ngAcceptInputType_checked: boolean | string;
375392
static ngAcceptInputType_indeterminate: boolean | string;
376393
static ngAcceptInputType_disabled: boolean | string;

src/material/checkbox/checkbox.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
[disabled]="disabled"
1111
[attr.name]="name"
1212
[tabIndex]="tabIndex"
13-
[indeterminate]="indeterminate"
1413
[attr.aria-label]="ariaLabel || null"
1514
[attr.aria-labelledby]="ariaLabelledby"
1615
[attr.aria-checked]="_getAriaChecked()"

src/material/checkbox/checkbox.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
Output,
2626
ViewChild,
2727
ViewEncapsulation,
28+
AfterViewInit,
2829
} from '@angular/core';
2930
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
3031
import {
@@ -132,7 +133,7 @@ const _MatCheckboxMixinBase:
132133
changeDetection: ChangeDetectionStrategy.OnPush
133134
})
134135
export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAccessor,
135-
AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple,
136+
AfterViewInit, AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple,
136137
FocusableOption {
137138

138139
/**
@@ -236,6 +237,10 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc
236237
this._clickAction = this._clickAction || this._options.clickAction;
237238
}
238239

240+
ngAfterViewInit() {
241+
this._syncIndeterminate(this._indeterminate);
242+
}
243+
239244
// TODO: Delete next major revision.
240245
ngAfterViewChecked() {}
241246

@@ -282,7 +287,7 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc
282287
get indeterminate(): boolean { return this._indeterminate; }
283288
set indeterminate(value: boolean) {
284289
const changed = value != this._indeterminate;
285-
this._indeterminate = value;
290+
this._indeterminate = coerceBooleanProperty(value);
286291

287292
if (changed) {
288293
if (this._indeterminate) {
@@ -293,6 +298,8 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc
293298
}
294299
this.indeterminateChange.emit(this._indeterminate);
295300
}
301+
302+
this._syncIndeterminate(this._indeterminate);
296303
}
297304
private _indeterminate: boolean = false;
298305

@@ -471,6 +478,22 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc
471478
return `mat-checkbox-anim-${animSuffix}`;
472479
}
473480

481+
/**
482+
* Syncs the indeterminate value with the checkbox DOM node.
483+
*
484+
* We sync `indeterminate` directly on the DOM node, because in Ivy the check for whether a
485+
* property is supported on an element boils down to `if (propName in element)`. Domino's
486+
* HTMLInputElement doesn't have an `indeterminate` property so Ivy will warn during
487+
* server-side rendering.
488+
*/
489+
private _syncIndeterminate(value: boolean) {
490+
const nativeCheckbox = this._inputElement;
491+
492+
if (nativeCheckbox) {
493+
nativeCheckbox.nativeElement.indeterminate = value;
494+
}
495+
}
496+
474497
static ngAcceptInputType_disabled: boolean | string;
475498
static ngAcceptInputType_required: boolean | string;
476499
static ngAcceptInputType_disableRipple: boolean | string;

tools/public_api_guard/material/checkbox.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export declare function MAT_CHECKBOX_DEFAULT_OPTIONS_FACTORY(): MatCheckboxDefau
1313

1414
export declare const MAT_CHECKBOX_REQUIRED_VALIDATOR: Provider;
1515

16-
export declare class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAccessor, AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple, FocusableOption {
16+
export declare class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAccessor, AfterViewInit, AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple, FocusableOption {
1717
_animationMode?: string | undefined;
1818
_inputElement: ElementRef<HTMLInputElement>;
1919
_onTouched: () => any;
@@ -40,6 +40,7 @@ export declare class MatCheckbox extends _MatCheckboxMixinBase implements Contro
4040
_onLabelTextChange(): void;
4141
focus(origin?: FocusOrigin, options?: FocusOptions): void;
4242
ngAfterViewChecked(): void;
43+
ngAfterViewInit(): void;
4344
ngOnDestroy(): void;
4445
registerOnChange(fn: (value: any) => void): void;
4546
registerOnTouched(fn: any): void;

0 commit comments

Comments
 (0)