An AngularJS pattern for “all” checkboxes

Recently I had to do an interface at work where there were a list of items, each with a separate checkbox, and a separate “all” checkbox which would check or uncheck all of them. At first that doesn’t seem very complicated but it’s an easy interface to mess up because you want the “all” to become checked if the user manually selects every child checkbox. Or conversely, if “all” is checked then you want it to automatically uncheck if even one child is unchecked.

My page had three separate sections with different lists and an all checkbox for each one. I had done my original design with an extra $scope variable representing the “all” checkbox and used a watch, but it still managed to mess up in certain circumstances. It was overly complicated and didn’t work 100% of the time. So my colleague challenged me to build it without the extra $scope variable because he was certain that was the key to getting a flawless solution. Now that I’ve done it, I agree completely.

Here’s a Plnkr with a running copy of the code so you can play with it:

But I just wanted to point out that what makes this work is really this line here. Instead of having the “all” checkbox reflect some variable via ng-model binding, I’ve just hooked it to two functions which handle the action it should perform (no more watch) and another which governs when it does and doesn’t appear checked.

  <input type="checkbox" ng-click="allNeedsClicked()" 
      ng-checked="allNeedsMet()" />All needs

In the next day or two I’m going to add this one to my AngularJS example page but I figured if I wrote about it now I would be more likely to get it done.

11 thoughts on “An AngularJS pattern for “all” checkboxes

  1. Christoffer

    This works great, I’m just having a hard time wrapping my head around how this actually works. I understand the part of the parent checkbox when you click it all other checkboxes become checked and vise versa. The part i don’t get is how can clicking any of the checkboxes in the list impact the parent checkbox and run it’s functions? Is it be because of angulars digest cycle constantly running the function in the ng-checked directive?

    1. John Munsch Post author

      AngularJS runs its digest cycle in response to certain events, constantly might imply something that is timer based or running continuously. In this case, the change in the status of the other checkboxes does run a digest cycle so the parent’s checkbox gets updated whenever one of them changes.

    1. John Munsch Post author

      Perhaps try again, sometimes Plunker gets overwhelmed and doesn’t work right. But I just double checked it and it seemed to be working and I made sure I wasn’t logged in so I wasn’t seeing something that wasn’t visible to everybody.

  2. Pierre

    Very useful, thank you John! And bonus points for using underscore. Another option would have been to use _.every with todo.done instead of a reduce and a compare with the number of items.

    I appreciate your post!


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s