"Select All" Checkboxes using Blazor

I was wondering if anyone has information on how to implement a "Select All" checkbox using Blazor for a collection of checkboxes? There's plenty of examples using JavaScript/jQuery, but was trying to do it with C# instead.

Here's what I'm working with right now. This code works adding the months selected to the list, but when using the "select all" checkbox, the other boxes are not showing checked.

Note: @Months[0].MonthName = Select All

<ul class="checkbox-grid">
  <li>
    <input type="checkbox"
      @onchange="EventArgs => { CheckAllMonths(Months[0], EventArgs.Value); }" />
    <label for="@Months[0].MonthId" id="checkboxLabel">@Months[0].MonthName</label>
  </li>
</ul>
@{
  for (int i = 1; i < Months.Count(); i++)
  {
    int j = i;
    <ul class="checkbox-grid">
      <li>
        <input type="checkbox" name="@Months[j].IsMonthChecked"
          @onchange="EventArgs => { CheckManualMonth(Months[j], EventArgs.Value); }" />
        <label for="@Months[j].MonthId" id="checkboxLabel">@Months[j].MonthName</label>
      </li>
    </ul>
  }
}

@code {
  List<Month> MonthList = new List<Month>();

  void CheckAllMonths(Month month, object checkValue)
  {
    if((bool)checkValue)
    {
      foreach(var item in Months)
      {
        CheckManualMonth(item, checkValue);
      }
    }
    else
    {
      foreach(var item in Months)
      {
        CheckManualMonth(item, checkValue);
      }
    }
  }

  void CheckManualMonth(Month month, object checkedValue)
  {
    if((bool)checkedValue)
    {
      if(!MonthList.Contains(month))
      {
        MonthList.Add(month);
        month.IsMonthChecked = true;
      }
    }
    else
    {
      if(MonthList.Contains(month))
      {
        MonthList.Remove(month);
        month.IsMonthChecked = false;
      }
    }
  }
}

Initialize Months

  private void GetMonthChecklist()
  {
    List<Month> months = new List<Month>()
    {
      new Month{MonthId = 0, MonthName = "All Months", IsMonthChecked = false},
      new Month{MonthId = 1, MonthName = "Jan", IsMonthChecked = false},
      new Month{MonthId = 2, MonthName = "Feb", IsMonthChecked = false},
      new Month{MonthId = 3, MonthName = "Mar", IsMonthChecked = false},
      new Month{MonthId = 4, MonthName = "Apr", IsMonthChecked = false},
      new Month{MonthId = 5, MonthName = "May", IsMonthChecked = false},
      new Month{MonthId = 6, MonthName = "Jun", IsMonthChecked = false},
      new Month{MonthId = 7, MonthName = "Jul", IsMonthChecked = false},
      new Month{MonthId = 8, MonthName = "Aug", IsMonthChecked = false},
      new Month{MonthId = 9, MonthName = "Sep", IsMonthChecked = false},
      new Month{MonthId = 10, MonthName = "Oct", IsMonthChecked = false},
      new Month{MonthId = 11, MonthName = "Nov", IsMonthChecked = false},
      new Month{MonthId = 12, MonthName = "Dec", IsMonthChecked = false}
    };

    Months = months.ToList();
  }

You do not bind the value to your checkbox. Actualy the easiest way to bind input's checked attribute is to use the InputCheckbox

    @foreach(var month in Months)
    {
        <ul class="checkbox-grid">            
            <li>
                <InputCheckbox ValueExpression="() => month.IsMonthChecked" Value="month.IsMonthChecked" ValueChanged="() => CheckManualMonth(month)" />
                <label for="@month.MonthId" id="checkboxLabel">@month.MonthName</label>
            </li>
        </ul>
    }

I believe it should be rather simple. How I implemeted in my project is like:

Header CheckBox

<input type="checkbox" id="SelectAllHeader" 
    @onchange="EventArgs => { CheckAllExpense(_allSelected, EventArgs.Value); }" /></th>

Body CheckBox

@foreach (var extExpense in _extendedExpenses)
{
    _iCount++;
    <tr class="text-sm @*row spinner-grow-sm*@">
        <td class="text-left">@_iCount</td>
        <th scope="row" @key="extExpense">
            <input type="checkbox" id="@extExpense.expense.Id" @bind="@extExpense.IsChecked" />
        </th>
    </tr>
}

and in the code:

void CheckAllExpense(bool headerChecked, object checkValue)
{
    bool isChecked = (bool)checkValue;
    _extendedExpenses.ToList().ForEach(e => e.IsChecked = isChecked);
}

Refer the entier code in github: https://github.com/DeepakkSHAW/ExpenseTracker.Server

Hope it can give you some idea How to change the approach.

I figured it out. First, I'm sticking to the original list I created in the InitializeData class. I used @bind-Value for two-way binding and @onclick to call the methods. The CheckManualMonth method also deselects the "Select All" checkbox if another month is deselected.

Thanks everyone for the help!

<fieldset class="group">
        <legend>Month</legend>
        <ul class="checkbox-grid">
          <li>                
            <InputCheckbox 
              @bind-Value="Months[0].IsMonthChecked" 
              @onclick="() => CheckAllMonths(Months[0])"/>
            <label for="@Months[0].MonthId" id="checkboxLabel">
              @Months[0].MonthName
            </label>
          </li>            
        </ul>        
        @{ 
            for(var i = 1; i < Months.Count(); i++)
            {
                var j = i;
                <ul class="checkbox-grid">
                  <li>
                    <InputCheckbox 
                      @bind-Value="Months[j].IsMonthChecked" 
                      @onclick="() => CheckManualMonth(Months[j])"/>
                    <label for="@Months[j].MonthId" id="checkboxLabel">
                      @Months[j].MonthName
                    </label>
                  </li>
                </ul>
            }
        }        
    </fieldset>

void CheckAllMonths(Month month)
    {
        if(month.IsMonthChecked == false)
        {
            foreach(var item in Months)
            {
                item.IsMonthChecked = true;
            }
        }
        else
        {
            foreach(var item in Months)
            {
                item.IsMonthChecked = false;
            }
        }
    }

    void CheckManualMonth(Month month)
    {
        if(month.IsMonthChecked == false)
        {
            month.IsMonthChecked = true;
        }
        else
        {
            month.IsMonthChecked = false;
            Months[0].IsMonthChecked = false;
        }
    }

Comments
  • Can you provide an example of what you're looking for? Are you looking for a separate checkbox that can toggle other checkboxes as well?
  • Just did. Like I said in the updated code, the select all checkbox is adding all months to the MonthList, but the UI is not showing them checked.
  • Have you tried setting month.IsMonthChecked = true before adding it to the list?
  • jcruz, yes I've tried that as well, still doesn't work
  • In your markup you are using a Months variable. Where is that defined/set? The one in your code block is named MonthsList not Months