Components

Checkbox Select All

A Stimulus controller for managing checkbox lists.


Video Tutorial

Chris Oliver from GoRails has released a presentation video on how to use this package with a real life example with Ruby on Rails.

👉 Take a look: Bulk Operations in Rails

Installation

  1. Install the package

    Terminal
    $ yarn add @stimulus-components/checkbox-select-all
    
  2. Register the controller in your application

    app/javascript/controllers/index.js
    import { Application } from '@hotwired/stimulus'
    import CheckboxSelectAll from '@stimulus-components/checkbox-select-all'
    
    const application = Application.start()
    application.register('checkbox-select-all', CheckboxSelectAll)
    

Example

Checkbox Select All

Usage

Without Rails

app/views/index.html.erb
<table data-controller="checkbox-select-all">
  <tbody>
    <tr>
      <td class="block">
        <label>
          <input type="checkbox" data-checkbox-select-all-target="checkboxAll" />
          <span>Select All / Deselect All</span>
        </label>
      </td>

      <td class="block">
        <label>
          <input type="checkbox" data-checkbox-select-all-target="checkbox" value="1" />
          <span>Team 1</span>
        </label>
      </td>

      <td class="block">
        <label>
          <input type="checkbox" data-checkbox-select-all-target="checkbox" checked="checked" value="2" />
          <span>Team 2</span>
        </label>
      </td>

      <td class="block">
        <label>
          <input type="checkbox" data-checkbox-select-all-target="checkbox" value="3" />
          <span>Team 3</span>
        </label>
      </td>
    </tr>
  </tbody>
</table>

With Rails

In your models:

app/models/user.rb
class User < ApplicationRecord
  has_many :teams
end
app/models/team.rb
class Team < ApplicationRecord
  belongs_to :user
end

In your controller:

app/controllers/users_controller.rb
class UsersController < ApplicationController
  def update
    if user.update(user_params)
      redirect_to users_path
    else
      render :edit
    end
  end

  private

  def user_params
    params
      .require(:user)
       .permit(
         team_ids: []
       )
  end
end
app/views/index.html
<%= form_with model: @user, data: { controller: 'checkbox-select-all' } do |f| %>
  <label>
    <input type="checkbox" data-checkbox-select-all-target="checkboxAll" />
    <span>Select All / Deselect All</span>
  </label>

  <%= f.collection_check_boxes :team_ids, Team.all, :id, :name do |b| %>
    <%= b.label do %>
      <%= b.check_box data: { checkbox_select_all_target: 'checkbox' } %>
      <%= b.text %>
    <% end %>
  <% end %>
<% end %>

Configuration

AttributeDefaultDescriptionOptional
data-checkbox-select-all-disable-indeterminate-valuefalseDisable the indeterminate state.
data-checkbox-select-all-ignore-disabled-valuefalseIgnore the disabled checkboxes in the indeterminate state.

Disabled checkboxes

The checkboxAll target never changes a disabled checkbox, because the user cannot change it and the browser does not submit it.

By default, the disabled checkboxes are still counted in the indeterminate state. If one disabled checkbox stays unchecked, the checkboxAll target stays indeterminate after a "Select All" click:

<form data-controller="checkbox-select-all">
  <input type="checkbox" data-checkbox-select-all-target="checkboxAll" />

  <input type="checkbox" data-checkbox-select-all-target="checkbox" />
  <input type="checkbox" data-checkbox-select-all-target="checkbox" disabled />
</form>

Set data-checkbox-select-all-ignore-disabled-value="true" to count only the checkboxes that the checkboxAll target can change. The indeterminate state then disappears when all the enabled checkboxes are checked.

This value has no effect when data-checkbox-select-all-disable-indeterminate-value is true, because there is no indeterminate state to compute.

Extending Controller

You can use inheritance to extend the functionality of any Stimulus component:

app/javascript/controllers/checkbox_select_all_controller.js
import CheckboxSelectAll from "@stimulus-components/checkbox-select-all"

export default class extends CheckboxSelectAll {
  connect() {
    super.connect()
    console.log("Do what you want here.")

    // Get all checked checkboxes
    this.checked

    // Get all unchecked checkboxes
    this.unchecked

    // Get all enabled checkboxes
    this.enabled

    // Get all disabled checkboxes
    this.disabled
  }
}

This controller will automatically have access to targets defined in the parent class.

If you override the connect, disconnect or any other methods from the parent, you'll want to call super.method() to make sure the parent functionality is executed.