From f61ed4df4f963c0895cfe080f5d48335377613be Mon Sep 17 00:00:00 2001
From: Steve Sanderson
Date: Tue, 1 May 2018 16:40:07 +0100
Subject: [PATCH] For checkboxes, bind to 'checked'. Fix special property
handling in BrowserRenderer.ts. Fixes #659 and #703
* Stop the value<-->checked conversions for checkboxes. Just use native 'checked' property. Fixes #703
* Properly handle removal of 'checked' and 'value' attributes
* E2E coverage for removing 'value'
---
.../src/Rendering/BrowserRenderer.ts | 85 ++++++++++++-------
.../Components/BindAttributes.cs | 3 +-
.../TestComponent.codegen.cs | 2 +-
.../TestComponent.mappings.txt | 2 +-
.../Tests/BindTest.cs | 37 +++++++-
.../BasicTestApp/BindCasesComponent.cshtml | 6 ++
6 files changed, 98 insertions(+), 37 deletions(-)
diff --git a/src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/BrowserRenderer.ts b/src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/BrowserRenderer.ts
index 2a95198c5b..10f382b4f9 100644
--- a/src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/BrowserRenderer.ts
+++ b/src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/BrowserRenderer.ts
@@ -84,7 +84,11 @@ export class BrowserRenderer {
const element = getLogicalChild(parent, childIndexAtCurrentDepth + siblingIndex);
if (element instanceof HTMLElement) {
const attributeName = renderTreeEdit.removedAttributeName(edit)!;
- element.removeAttribute(attributeName);
+ // First try to remove any special property we use for this attribute
+ if (!this.tryApplySpecialProperty(element, attributeName, null)) {
+ // If that's not applicable, it's a regular DOM attribute so remove that
+ element.removeAttribute(attributeName);
+ }
} else {
throw new Error(`Cannot remove attribute from non-element child`);
}
@@ -205,53 +209,76 @@ export class BrowserRenderer {
return;
}
- if (attributeName === 'value') {
- if (this.tryApplyValueProperty(toDomElement, renderTreeFrame.attributeValue(attributeFrame))) {
- return; // If this DOM element type has special 'value' handling, don't also write it as an attribute
- }
+ // First see if we have special handling for this attribute
+ if (!this.tryApplySpecialProperty(toDomElement, attributeName, attributeFrame)) {
+ // If not, treat it as a regular string-valued attribute
+ toDomElement.setAttribute(
+ attributeName,
+ renderTreeFrame.attributeValue(attributeFrame)!
+ );
}
-
- // Treat as a regular string-valued attribute
- toDomElement.setAttribute(
- attributeName,
- renderTreeFrame.attributeValue(attributeFrame)!
- );
}
- private tryApplyValueProperty(element: Element, value: string | null) {
+ private tryApplySpecialProperty(element: Element, attributeName: string, attributeFrame: RenderTreeFramePointer | null) {
+ switch (attributeName) {
+ case 'value':
+ return this.tryApplyValueProperty(element, attributeFrame);
+ case 'checked':
+ return this.tryApplyCheckedProperty(element, attributeFrame);
+ default:
+ return false;
+ }
+ }
+
+ private tryApplyValueProperty(element: Element, attributeFrame: RenderTreeFramePointer | null) {
// Certain elements have built-in behaviour for their 'value' property
switch (element.tagName) {
case 'INPUT':
case 'SELECT':
- case 'TEXTAREA':
- if (isCheckbox(element)) {
- (element as HTMLInputElement).checked = value === '';
- } else {
- (element as any).value = value;
+ case 'TEXTAREA': {
+ const value = attributeFrame ? renderTreeFrame.attributeValue(attributeFrame) : null;
+ (element as any).value = value;
- if (element.tagName === 'SELECT') {
- //