javascriptangularjscheckboxangularjs-ng-repeatangularjs-ng-checked

How to check all children based on parent while also checking parent based on children?


Plnkr: https://plnkr.co/edit/Tt96EE2rruy1HAudRVJR?p=preview

I have the following nested loops of checkboxes:

<ul>
  <li ng-repeat="continent in destinations">
    <input type="checkbox" ng-model="continent.selected">
    {{continent.name}} ({{continent.countries_selected}} / {{continent.countries.length}}) - {{continent.all_selected}}
    <ul>
      <li ng-repeat="country in continent.countries">
        <input type="checkbox" ng-model="country.selected" ng-checked="continent.selected">
        {{country.name}}
      </li>
    </ul>
  </li>
</ul>

And this is the code that detects ($watch) whether some or all children checkboxes have been checked, if so, parent checkbox gets checked as well.

That works fine.

But, when I check the parent box, it doesn't check.

What I want to achieve is that when I check a parent checkbox, all its children get checked as well and when I uncheck the parent checkbox, all its children get unchecked.

$scope.$watch('destinations', function(destinations){

  var total_selected = 0;

  angular.forEach(destinations, function(continent){

    continent.countries_selected = 0;

    angular.forEach(continent.countries, function(country){

      total_selected += country.selected ? 1 : 0

      continent.countries_selected += country.selected ? 1 : 0

      if (continent.countries_selected == continent.countries.length) {
        continent.selected = true;
      } else {
        continent.selected = false;
      }

    });

  });

  $scope.select_all = function(continent){
    continent.selected = true;
  }

  $scope.total_selected = total_selected;

}, true);

Solution

  • you can try it . call a function on change of continent value

    <input type="checkbox" ng-model="continent.selected" ng-change="parentChange($index)">
    

    and in controller: add another function

    $scope.parentChange = function(index) {
        angular.forEach( $scope.destinations[index].countries, function(country) {
          country.selected = $scope.destinations[index].selected;
        });
      };
    

    and may be no need to add ng-checked="continent.selected" for country checkbox.

    use

    <input type="checkbox" ng-model="country.selected">
    

    instead of

    <input type="checkbox" ng-model="country.selected" ng-checked="continent.selected">
    

    Plunker DEMO LINK