Kris van der Mast
Kris van der Mast

Reputation: 16613

Blazor checkbox onchange event with parameter

The following code works for me:

@if (data == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <button class="btn btn-primary" @onclick="Save">Save all changes</button>

    <table class="table">
        <thead>
            <tr>
                <th>Concern ID</th>
                <th>CDC</th>
                <th>Context</th>
                <th>Reporting</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var c in data)
            {
                <tr>
                    <td>@c.ConcernId</td>
                    <td><input type="checkbox" @bind="@c.PassingAllowed" /></td>
                    <td><input type="checkbox" @bind="@c.ContextPassingAllowed" /></td>
                    <td><input type="checkbox" @bind="@c.ReportingPassingAllowed" /></td>
                </tr>
            }
        </tbody>
    </table>
}

@code{
    private ConcernData[] data;  

    protected override async Task OnInitializedAsync()
    {
        await GetData().ConfigureAwait(false);
    }

    private async Task GetData()
    {
        data = await Http.GetFromJsonAsync<ConcernData[]>("ConcernFilter").ConfigureAwait(false);
    }

    private async Task Save()
    {
        await Http.PostAsJsonAsync<ConcernData[]>("ConcernFilter/Update", data).ConfigureAwait(false);
    }

    private async Task Update(int concernId)
    {
        Console.Write(concernId);
    }
}

However this sends over all the data (changed and unchanged) back to the server where I need to figure out (or simply update one by one) which data needs an update in the databases.

It doesn't feel right as I'm sending too much data over the wire and sending too many update statements to the databases (3 in this case).

I can think of several way to tackle this:

  1. on the client compare the altered list with an original list and only send the items to the server that really need an update.
  2. find a way to write in Blazor for a checkbox in such a list how to call the Update method and passing the correct concernId as a parameter.

I'm looking for help to accomplish option 2.

Upvotes: 1

Views: 2365

Answers (1)

Artak
Artak

Reputation: 2887

There is no "magic" in Blazor. It has no way to know which particular rows have been updated, unless you actually track that. And that's only half of the story. Your code - the Save() method, actually posts the full data array to the server.

It sounds like what you're looking for is to address both of these concerns. For that you will need:

  1. Logic to track the changed rows and potentially storing these in a separate array
  2. Update your Save method to use that new list instead, to send to the server only the data from the changed rows, not the entire data set.

The piece which is Blazor specific here, is how you actually detect the rows which were changed. You can actually simplify this by slightly modifying your data model, by introducing state tracking logic and exposing that through a property. The following is a simple demonstration only:

public class ConcernData
{
  internal bool StateChanged {get; private set;}

  public bool PassingAllowed
  {
    get => _passingAllowed;
    set
    {
      if (value != _passingAllowed)
      {
        _passingAllowed = value;
        StateChanged = true;
      }
    }
  }

  // Similar change detection logic goes for the rest of the properties
}

Note, that this is very naive implementation, which doesn't account for situations, where the users changes the data back to its original value again. But, this will enable you to update the Save method as follows:

private async Task Save()
{
  await Http.PostAsJsonAsync<ConcernData[]>("ConcernFilter/Update", data.Where(c=>c.StateChanged)).ConfigureAwait(false);
}

Hope this helps.

Upvotes: 2

Related Questions