. Net Core Blazor - Javascript ошибка при использовании привязки флажка ввода с <tr>при нажатии - PullRequest
2 голосов
/ 09 февраля 2020

Я пишу компонент Blazor для серверного приложения Blazor, который будет отображать таблицу данных и позволять выбрать одну или несколько строк. Идея заключается в том, что в первом столбце таблицы будет установлен флажок, а в остальных столбцах - строка данных. Строка выбирается / отменяется, установив флажок ИЛИ, щелкнув в любом месте строки. Это делается путем привязки флажка ввода к bool объекта row и с помощью onclick для элемента tr.

<tr @onclick="() => item.Toggle()">
    <td><input type="checkbox" @bind="item.Selected" /></td>
    <td>@item.Number</td>
    <td>@item.Text</td>
</tr>

Обычно это работает. При щелчке по строке будет выбран ряд, установите значение bool равным true, и флажок будет установлен. Повторный щелчок по строке отменяет выбор строки, устанавливает значение bool равным false, и флажок будет снят. Все как и ожидалось. При установке флажка он также работает, однако снятие флажка приводит к ошибке времени выполнения javascript. Нижний колонтитул blazor-error-ui отображается со стандартным сообщением «Произошло непредвиденное исключение. Подробнее см. Инструменты разработчика браузера. Перезагрузка ».

Вот подробности из 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 в моем приложении использует класс Selectable, который принимает класс Row в качестве параметра и добавляет bool для выбора. Однако, чтобы упростить пример, я включил bool Selected в класс Row. Пример основан на стандартном шаблонном проекте на стороне сервера 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)
        };
    }
}

Если я удаляю onclick для элемента tr, он работает нормально. Так как onclick срабатывает каждый раз при щелчке по строке, я предполагаю, что существует некоторый конфликт с привязкой на флажке. Тем не менее, мне не хватает Javascript навыков для дальнейшего расследования. Я могу избежать этой ситуации, запустив onclick для каждого td элемента (кроме первого флажка), а не для всего tr, но это становится утомительным и немного уродливым, когда есть много столбцов. Поскольку это не удается в Blazor. js Мне интересно, может ли это быть ошибкой / ограничением Blazor.

Любые мысли приветствуются. Спасибо.

1 Ответ

3 голосов
/ 09 февраля 2020

Попробуйте следующий код ... Примечание: я внес некоторые изменения не потому, что они являются причиной проблемы, и т. Д. c. Я просто не могу не иметь свой собственный стиль. Тем не менее, вы должны сосредоточиться на том, как вы привязываетесь к элементам. Обратите внимание, что достаточно привязать атрибут checked флажка следующим образом: 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; }

 }

}

Я предполагал, что мне нужно использовать @bind, но я все еще не уверен, почему я могу ' t

Обычно вы можете использовать директиву @bind для создания двусторонней привязки данных между элементом Html и источником данных. Но в этом случае достаточно односторонней привязки данных, от источника данных до флажка, поскольку лямбда-выражение, запускаемое действием click элемента tr, переключает логическое свойство row.Selected. Следовательно, компонент повторно визуализируется, и флажок либо отмечен, либо не отмечен. в зависимости от предыдущего состояния.

Примечание: директива @bind при обработке компилятором создает два атрибута, которые ДОЛЖНЫ быть эквивалентны чему-то подобному, если вы примените директиву к флажку:

<td><input type="checkbox" checked="@row.Selected" @onchange="@((args) => row.Selected = (bool) args.Value)" /></td>

Если вы используете этот код вместо приведенного выше, ваше приложение все равно будет работать нормально, но, как вы уже поняли, событие изменения, вызванное для флажка, является излишним.

Но, вот и вот, если вы используете директиву @bind, позволяющую компилятору действовать от вашего имени, ваш код потерпит неудачу. Полагаю, это не сообщаемая ошибка.

Я надеюсь, что не усложнил ситуацию, добавив вышеуказанное дополнение ...

Надеюсь, это поможет ...

...