.Net Core Blazor - Javascript 使用输入复选框绑定 <tr> onclick 时出错
.Net Core Blazor - Javascript error using input checkbox binding with <tr> onclick
我正在为 Blazor 服务器端应用程序编写一个 Blazor 组件,它将显示 table 数据并允许 select 编辑一行或多行。这个想法是 table 的第一列中会有一个复选框,其余列中的行数据。通过单击复选框或单击行中的任意位置,该行是 selected/deselected。这是通过将输入复选框绑定到行对象上的布尔值并在 tr 元素上使用 onclick 来完成的。
<tr @onclick="() => item.Toggle()">
<td><input type="checkbox" @bind="item.Selected" /></td>
<td>@item.Number</td>
<td>@item.Text</td>
</tr>
一般都可以。单击该行将 select 该行,将 bool 值设置为 true,复选框将被选中。再次单击该行将取消select 该行,将 bool 值设置为 false,复选框将取消选中。一切如预期。选中复选框时它也有效,但是取消选中复选框会导致 javascript 运行时错误。 blazor-error-ui 页脚显示为标准消息 "An unexpected exception has occurred. See browser dev tools for details. Reload".
以下是来自 Chrome 控制台的详细信息
blazor.server.js:1 [2020-02-09T11:25:41.667Z] Information: Normalizing '_blazor' to 'https://localhost:44374/_blazor'.
blazor.server.js:1 [2020-02-09T11:25:41.874Z] Information: WebSocket connected to wss://localhost:44374/_blazor?id=58aEAiJBVZFuzpm9Sn_HdA.
blazor.server.js:15 [2020-02-09T11:25:49.676Z] Error: There was an error applying batch 10.
e.log @ blazor.server.js:15
blazor.server.js:8 Uncaught (in promise) TypeError: Cannot read property 'parentNode' of undefined
at Object.e [as removeLogicalChild] (blazor.server.js:8)
at e.applyEdits (blazor.server.js:8)
at e.updateComponent (blazor.server.js:8)
at Object.t.renderBatch (blazor.server.js:1)
at e.<anonymous> (blazor.server.js:15)
at blazor.server.js:15
at Object.next (blazor.server.js:15)
at blazor.server.js:15
at new Promise (<anonymous>)
at r (blazor.server.js:15)
blazor.server.js:15 [2020-02-09T11:25:49.864Z] Error: System.AggregateException: One or more errors occurred. (TypeError: Cannot read property 'parentNode' of undefined)
---> System.InvalidOperationException: TypeError: Cannot read property 'parentNode' of undefined
at Microsoft.AspNetCore.Components.RenderTree.Renderer.InvokeRenderCompletedCallsAfterUpdateDisplayTask(Task updateDisplayTask, Int32[] updatedComponents)
--- End of inner exception stack trace ---
我的应用程序中的 Blazor 组件使用 class Selectable
将 Row
class 作为参数并为 selection 添加布尔值.但是,为了简化示例,我在 Row
class 中包含了 bool Selected
。该示例基于标准的 Blazor 服务器端模板项目,并添加了一个 Blazor 页面。这是该页面的完整代码:
@page "/test"
@if (data == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table table-hover">
<thead>
<tr>
<th>Select</th>
<th>Number</th>
<th>Text</th>
</tr>
</thead>
<tbody>
@foreach (var item in data)
{
<tr @onclick="() => item.Toggle()">
<td><input type="checkbox" @bind="item.Selected" /></td>
<td>@item.Number</td>
<td>@item.Text</td>
</tr>
}
</tbody>
</table>
}
@code
{
private List<Row> data;
private class Row
{
public bool Selected;
public int Number;
public string Text;
public Row(int number)
{
Selected = false;
Number = number;
Text = $"Item {number}";
}
public void Toggle() => Selected = !Selected;
}
protected override void OnInitialized()
{
data = new List<Row>
{
new Row(1),
new Row(2),
new Row(3)
};
}
}
如果我删除 tr
元素的 onclick
,它就可以正常工作。由于 onclick
会在单击该行时触发,我猜测与复选框上的绑定存在一些冲突。但是,我没有足够的 Javascript 技能来进一步调查。我可以通过为每个 td
元素(第一个复选框除外)而不是整个 tr
触发 onclick
来避免这种情况,但是当有很多元素时,这会变得乏味且有点难看列。由于这在 blazor.js 内失败,我想知道它是否可能是 Blazor 的 bug/limitation。
欢迎任何想法。谢谢。
试试下面的代码...注意:我做了一些改动不是因为它们是问题的原因等,我只是忍不住要有自己的风格。但是,您应该关注如何绑定到元素。请注意,像这样绑定到复选框的选中属性就足够了:checked="@row.Selected"
。
我希望您正在寻找这样的解决方案...
<table class="table table-hover">
<thead>
<tr>
<th>Select</th>
<th>Number</th>
<th>Text</th>
</tr>
</thead>
<tbody>
@foreach (var row in rows)
{
<tr @onclick="@(() => row.Selected = !row.Selected)">
<td><input type="checkbox" checked="@row.Selected" /></td>
<td>@row.Number</td>
<td>@row.Text</td>
</tr>
}
</tbody>
</table>
@code
{
List<Row> rows = Enumerable.Range(1, 10).Select(i => new Row { Selected =
false, Number = i, Text = $"Item {i}" }).ToList();
private class Row
{
public bool Selected { get; set; }
public int Number { get; set; }
public string Text { get; set; }
}
}
I had assumed I had to use @bind but I'm still not sure why I can't
通常您可以使用@bind 指令在Html 元素和数据源之间创建双向数据绑定。但在这种情况下,从数据源到复选框的单向数据绑定就足够了,因为 tr 元素上的单击操作触发的 lambda 表达式会切换布尔值 row.Selected 属性。因此,组件被重新渲染,复选框被选中或取消选中。取决于之前的状态。
注意:@bind 指令在编译器处理时会创建两个属性,如果您将指令应用于复选框,这两个属性应该等同于这样的东西:
<td><input type="checkbox" checked="@row.Selected" @onchange="@((args) => row.Selected = (bool) args.Value)" /></td>
如果您使用这段代码而不是上面的代码,您的应用程序仍然可以正常工作,但您现在一定已经明白,为复选框引发的更改事件是多余的。
但是,你瞧,如果您使用@bind 指令,让编译器代表您执行操作,您的代码将会失败。我想这是未报告的错误。
我希望我没有通过添加上述内容使事情变得相当复杂...
希望这对您有所帮助...
我正在为 Blazor 服务器端应用程序编写一个 Blazor 组件,它将显示 table 数据并允许 select 编辑一行或多行。这个想法是 table 的第一列中会有一个复选框,其余列中的行数据。通过单击复选框或单击行中的任意位置,该行是 selected/deselected。这是通过将输入复选框绑定到行对象上的布尔值并在 tr 元素上使用 onclick 来完成的。
<tr @onclick="() => item.Toggle()">
<td><input type="checkbox" @bind="item.Selected" /></td>
<td>@item.Number</td>
<td>@item.Text</td>
</tr>
一般都可以。单击该行将 select 该行,将 bool 值设置为 true,复选框将被选中。再次单击该行将取消select 该行,将 bool 值设置为 false,复选框将取消选中。一切如预期。选中复选框时它也有效,但是取消选中复选框会导致 javascript 运行时错误。 blazor-error-ui 页脚显示为标准消息 "An unexpected exception has occurred. See browser dev tools for details. Reload".
以下是来自 Chrome 控制台的详细信息
blazor.server.js:1 [2020-02-09T11:25:41.667Z] Information: Normalizing '_blazor' to 'https://localhost:44374/_blazor'.
blazor.server.js:1 [2020-02-09T11:25:41.874Z] Information: WebSocket connected to wss://localhost:44374/_blazor?id=58aEAiJBVZFuzpm9Sn_HdA.
blazor.server.js:15 [2020-02-09T11:25:49.676Z] Error: There was an error applying batch 10.
e.log @ blazor.server.js:15
blazor.server.js:8 Uncaught (in promise) TypeError: Cannot read property 'parentNode' of undefined
at Object.e [as removeLogicalChild] (blazor.server.js:8)
at e.applyEdits (blazor.server.js:8)
at e.updateComponent (blazor.server.js:8)
at Object.t.renderBatch (blazor.server.js:1)
at e.<anonymous> (blazor.server.js:15)
at blazor.server.js:15
at Object.next (blazor.server.js:15)
at blazor.server.js:15
at new Promise (<anonymous>)
at r (blazor.server.js:15)
blazor.server.js:15 [2020-02-09T11:25:49.864Z] Error: System.AggregateException: One or more errors occurred. (TypeError: Cannot read property 'parentNode' of undefined)
---> System.InvalidOperationException: TypeError: Cannot read property 'parentNode' of undefined
at Microsoft.AspNetCore.Components.RenderTree.Renderer.InvokeRenderCompletedCallsAfterUpdateDisplayTask(Task updateDisplayTask, Int32[] updatedComponents)
--- End of inner exception stack trace ---
我的应用程序中的 Blazor 组件使用 class Selectable
将 Row
class 作为参数并为 selection 添加布尔值.但是,为了简化示例,我在 Row
class 中包含了 bool Selected
。该示例基于标准的 Blazor 服务器端模板项目,并添加了一个 Blazor 页面。这是该页面的完整代码:
@page "/test"
@if (data == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table table-hover">
<thead>
<tr>
<th>Select</th>
<th>Number</th>
<th>Text</th>
</tr>
</thead>
<tbody>
@foreach (var item in data)
{
<tr @onclick="() => item.Toggle()">
<td><input type="checkbox" @bind="item.Selected" /></td>
<td>@item.Number</td>
<td>@item.Text</td>
</tr>
}
</tbody>
</table>
}
@code
{
private List<Row> data;
private class Row
{
public bool Selected;
public int Number;
public string Text;
public Row(int number)
{
Selected = false;
Number = number;
Text = $"Item {number}";
}
public void Toggle() => Selected = !Selected;
}
protected override void OnInitialized()
{
data = new List<Row>
{
new Row(1),
new Row(2),
new Row(3)
};
}
}
如果我删除 tr
元素的 onclick
,它就可以正常工作。由于 onclick
会在单击该行时触发,我猜测与复选框上的绑定存在一些冲突。但是,我没有足够的 Javascript 技能来进一步调查。我可以通过为每个 td
元素(第一个复选框除外)而不是整个 tr
触发 onclick
来避免这种情况,但是当有很多元素时,这会变得乏味且有点难看列。由于这在 blazor.js 内失败,我想知道它是否可能是 Blazor 的 bug/limitation。
欢迎任何想法。谢谢。
试试下面的代码...注意:我做了一些改动不是因为它们是问题的原因等,我只是忍不住要有自己的风格。但是,您应该关注如何绑定到元素。请注意,像这样绑定到复选框的选中属性就足够了:checked="@row.Selected"
。
我希望您正在寻找这样的解决方案...
<table class="table table-hover">
<thead>
<tr>
<th>Select</th>
<th>Number</th>
<th>Text</th>
</tr>
</thead>
<tbody>
@foreach (var row in rows)
{
<tr @onclick="@(() => row.Selected = !row.Selected)">
<td><input type="checkbox" checked="@row.Selected" /></td>
<td>@row.Number</td>
<td>@row.Text</td>
</tr>
}
</tbody>
</table>
@code
{
List<Row> rows = Enumerable.Range(1, 10).Select(i => new Row { Selected =
false, Number = i, Text = $"Item {i}" }).ToList();
private class Row
{
public bool Selected { get; set; }
public int Number { get; set; }
public string Text { get; set; }
}
}
I had assumed I had to use @bind but I'm still not sure why I can't
通常您可以使用@bind 指令在Html 元素和数据源之间创建双向数据绑定。但在这种情况下,从数据源到复选框的单向数据绑定就足够了,因为 tr 元素上的单击操作触发的 lambda 表达式会切换布尔值 row.Selected 属性。因此,组件被重新渲染,复选框被选中或取消选中。取决于之前的状态。
注意:@bind 指令在编译器处理时会创建两个属性,如果您将指令应用于复选框,这两个属性应该等同于这样的东西:
<td><input type="checkbox" checked="@row.Selected" @onchange="@((args) => row.Selected = (bool) args.Value)" /></td>
如果您使用这段代码而不是上面的代码,您的应用程序仍然可以正常工作,但您现在一定已经明白,为复选框引发的更改事件是多余的。
但是,你瞧,如果您使用@bind 指令,让编译器代表您执行操作,您的代码将会失败。我想这是未报告的错误。
我希望我没有通过添加上述内容使事情变得相当复杂...
希望这对您有所帮助...