28

I have a form that contains 3 checkboxes: "Select All", "Option 1", and "Option 2".

<form id="selectionForm">
    <input type="checkbox" ng-model="selectAll" >Select all
    <br>
    <input type="checkbox" ng-checked="selectAll" checked>Option 1
    <br>
    <input type="checkbox" ng-checked="selectAll">Option 2
</form>

On the initial page load I want only Option 1 to be checked. And then if the Select All checkbox gets checked it should automatically check Option 1 and Option 2 so all are selected.

The problem is on the initial page load the ng-checked="selectAll" gets evaluated which overrides my attempt to initially check only Option 1 (selectAll = false initially), so nothing is selected.

This seems like a simple problem to solve, but I can't figure out a solution... Thanks in advance for any insights or advice!

PSL
  • 123,204
  • 21
  • 253
  • 243
Cumulo Nimbus
  • 8,785
  • 9
  • 47
  • 68

3 Answers3

85

Another way to go about it is to use a model for the options, set default selection in the model and have your controller handle the logic of doing select all.

angular.module("app", []).controller("ctrl", function($scope){
  
  $scope.options = [
    {value:'Option1', selected:true}, 
    {value:'Option2', selected:false}
  ];
  
  $scope.toggleAll = function() {
     var toggleStatus = !$scope.isAllSelected;
     angular.forEach($scope.options, function(itm){ itm.selected = toggleStatus; });
   
  }
  
  $scope.optionToggled = function(){
    $scope.isAllSelected = $scope.options.every(function(itm){ return itm.selected; })
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">    </script>
<div ng-app="app" ng-controller="ctrl">
<form id="selectionForm">
    <input type="checkbox" ng-click="toggleAll()" ng-model="isAllSelected">Select all
    <br>
     <div ng-repeat = "option in options">
        <input type="checkbox" ng-model="option.selected" ng-change="optionToggled()">{{option.value}}
     </div>
</form>
  {{options}} 
</div>
PSL
  • 123,204
  • 21
  • 253
  • 243
  • 3
    This is actually a better way to do it. – Josep Dec 12 '14 at 21:22
  • Thanks for your answer. This seems like a much more angular way to go about implementing this type of functionality – Cumulo Nimbus Dec 12 '14 at 21:28
  • @CumuloNimbus You are welcome. Added a method to auto check the selectAll checkbox if you manually check all the check boxes and viceversa... – PSL Dec 12 '14 at 21:29
  • @CumuloNimbus Also note that i am using *[array.every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every)*, for this to work in older browsers you would need to add a shim mentioned in the linked MDN documentation. – PSL Dec 12 '14 at 21:30
  • Jinx ;) - I promise I didn't copy you're work, but they're oddly similar if you see my plunker. – Dylan Dec 12 '14 at 21:46
  • @Dylan oh no!! i never said anything.. :D Infact i just updated my answer, forgot about the other way around toggle.. :P – PSL Dec 12 '14 at 21:52
  • @PSL Found one bug in your solution. If Select All is checked and the user unchecks it, Option 1 and Option 2 should also be unchecked – Cumulo Nimbus Dec 12 '14 at 21:59
  • @CumuloNimbus did you check my demo? – PSL Dec 12 '14 at 22:00
  • @PSL nvm, you beat me to it! Thanks again – Cumulo Nimbus Dec 12 '14 at 22:00
  • @PSL I'm totally j/k it can be hard to tell in text, You're too fast man!! Quick draw - I'll catch up tho :) – Dylan Dec 12 '14 at 22:01
  • @Dylan haha you are being too generous.. :D – PSL Dec 12 '14 at 22:02
  • !important: Note that this will change the model value for the collection items and reflect this within the UI as "checked" -- **however, this still does not trigger the `ng-change` expression-evaluation.** – Cody Feb 19 '16 at 17:32
  • 1
    @Cody: `ng-change` expression will **NOT** be evaluated because the checkbox model value is changed programatically, instead of user interaction with checkbox. See https://docs.angularjs.org/api/ng/directive/ngChange – manikanta Sep 19 '16 at 13:03
  • Your answer was very helpfull! But yeah, for toggle all i needed to use ng-if instead of ng-model for true and false case, else wasn't working. – Andris Jun 07 '18 at 08:26
5

Try this:

<form id="selectionForm">
    <input type="checkbox" ng-model="selectAll" >Select all
    <br>
    <input type="checkbox" ng-checked="selectAll || option1" ng-init="option1=true" ng-model="option1">Option 1
    <br>
    <input type="checkbox" ng-checked="selectAll">Option 2
</form>
Josep
  • 12,926
  • 2
  • 42
  • 45
5

I like to use an ng-repeat for clarity on showing what you're selecting/un-selecting, basically you end up with a nice little object to base it all on, and adding to it is just easier.

Here's a Plunker

*Also notice how you can achieve allSelected? with a loop func and not a ton of html, and I'm sure this can be done with less spaghetti but it works *

app.controller('MainCtrl', function($scope) {

$scope.allSelected = false;

$scope.checkboxes = [{label: 'Option 1',checked: true}, {label: 'Option 2'}}}];

$scope.cbChecked = function(){
  $scope.allSelected = true;
  angular.forEach($scope.checkboxes, function(v, k) {
    if(!v.checked){
      $scope.allSelected = false;
    }
  });
}
$scope.toggleAll = function() {
    var bool = true;
    if ($scope.allSelected) {
      bool = false;
    }
    angular.forEach($scope.checkboxes, function(v, k) {
      v.checked = !bool;
      $scope.allSelected = !bool;
      });
   }
});
Dylan
  • 4,703
  • 1
  • 20
  • 23