Skip to content

Commit 8c04176

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 3052304 commit 8c04176

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
@@ -119,6 +119,7 @@ export class MatCheckbox implements AfterViewInit, OnDestroy, ControlValueAccess
119119
}
120120
set indeterminate(indeterminate) {
121121
this._indeterminate = coerceBooleanProperty(indeterminate);
122+
this._syncIndeterminate(this._indeterminate);
122123
}
123124
private _indeterminate = false;
124125

@@ -236,6 +237,7 @@ export class MatCheckbox implements AfterViewInit, OnDestroy, ControlValueAccess
236237
}
237238

238239
ngAfterViewInit() {
240+
this._syncIndeterminate(this._indeterminate);
239241
this._checkboxFoundation.init();
240242
}
241243

@@ -348,4 +350,19 @@ export class MatCheckbox implements AfterViewInit, OnDestroy, ControlValueAccess
348350
this._classes[cssClass] = active;
349351
this._changeDetectorRef.markForCheck();
350352
}
353+
354+
/**
355+
* Syncs the indeterminate value with the checkbox DOM node.
356+
*
357+
* We sync `indeterminate` directly on the DOM node, because in Ivy the check for whether a
358+
* property is supported on an element boils down to `if (propName in element)`. Domino's
359+
* HTMLInputElement doesn't have an `indeterminate` property so Ivy will warn during
360+
* server-side rendering.
361+
*/
362+
private _syncIndeterminate(value: boolean) {
363+
const nativeCheckbox = this._nativeCheckbox;
364+
if (nativeCheckbox) {
365+
nativeCheckbox.nativeElement.indeterminate = value;
366+
}
367+
}
351368
}

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
ViewChild,
2626
ViewEncapsulation,
2727
AfterViewChecked,
28+
AfterViewInit,
2829
} from '@angular/core';
2930
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
3031
import {
@@ -127,7 +128,7 @@ const _MatCheckboxMixinBase:
127128
changeDetection: ChangeDetectionStrategy.OnPush
128129
})
129130
export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAccessor,
130-
AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple,
131+
AfterViewInit, AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple,
131132
FocusableOption {
132133

133134
/**
@@ -216,6 +217,10 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc
216217
});
217218
}
218219

220+
ngAfterViewInit() {
221+
this._syncIndeterminate(this._indeterminate);
222+
}
223+
219224
// TODO: Delete next major revision.
220225
ngAfterViewChecked() {}
221226

@@ -262,7 +267,7 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc
262267
get indeterminate(): boolean { return this._indeterminate; }
263268
set indeterminate(value: boolean) {
264269
const changed = value != this._indeterminate;
265-
this._indeterminate = value;
270+
this._indeterminate = coerceBooleanProperty(value);
266271

267272
if (changed) {
268273
if (this._indeterminate) {
@@ -273,6 +278,8 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc
273278
}
274279
this.indeterminateChange.emit(this._indeterminate);
275280
}
281+
282+
this._syncIndeterminate(this._indeterminate);
276283
}
277284
private _indeterminate: boolean = false;
278285

@@ -450,4 +457,20 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc
450457

451458
return `mat-checkbox-anim-${animSuffix}`;
452459
}
460+
461+
/**
462+
* Syncs the indeterminate value with the checkbox DOM node.
463+
*
464+
* We sync `indeterminate` directly on the DOM node, because in Ivy the check for whether a
465+
* property is supported on an element boils down to `if (propName in element)`. Domino's
466+
* HTMLInputElement doesn't have an `indeterminate` property so Ivy will warn during
467+
* server-side rendering.
468+
*/
469+
private _syncIndeterminate(value: boolean) {
470+
const nativeCheckbox = this._inputElement;
471+
472+
if (nativeCheckbox) {
473+
nativeCheckbox.nativeElement.indeterminate = value;
474+
}
475+
}
453476
}

tools/public_api_guard/material/checkbox.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export declare const MAT_CHECKBOX_CONTROL_VALUE_ACCESSOR: any;
77

88
export declare const MAT_CHECKBOX_REQUIRED_VALIDATOR: Provider;
99

10-
export declare class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAccessor, AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple, FocusableOption {
10+
export declare class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAccessor, AfterViewInit, AfterViewChecked, OnDestroy, CanColor, CanDisable, HasTabIndex, CanDisableRipple, FocusableOption {
1111
_animationMode?: string | undefined;
1212
_inputElement: ElementRef<HTMLInputElement>;
1313
_onTouched: () => any;
@@ -33,6 +33,7 @@ export declare class MatCheckbox extends _MatCheckboxMixinBase implements Contro
3333
_onLabelTextChange(): void;
3434
focus(origin?: FocusOrigin, options?: FocusOptions): void;
3535
ngAfterViewChecked(): void;
36+
ngAfterViewInit(): void;
3637
ngOnDestroy(): void;
3738
registerOnChange(fn: (value: any) => void): void;
3839
registerOnTouched(fn: any): void;

0 commit comments

Comments
 (0)