nemo_87
nemo_87

Reputation: 4781

Select and deselect all check-boxes on click in AngularJs

I am having difficulties in understanding how to find out if some checkbox is selected or not in Angular.

This is the problem:

I have simple HTML table, on ng-change event I am calling one function that need to check if 'select all' checkbox is checked:

This is HTML:

<table class="table table-striped">
    <thead>
        <tr class="table-header">
            <th ng-if="!newTestSessionCtrl.formData.battery.id"><input type="checkbox" ng-model="selectedAll" ng-change="newTestSessionCtrl.isSelectAll()" /></th>
            <th>Test</th>
            <th>Available Time</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="row in newTestSessionCtrl.formData.battery.testDefinitions">
            <td ng-if="!newTestSessionCtrl.formData.battery.id"><input type="checkbox" ng-model="row.selected" ng-change="newTestSessionCtrl.isLabelChecked(); newTestSessionCtrl.validate()" /></td>
            <td>{{row.name}}</td>
            <td>{{(row.duration / 60) | number:0}} minutes</td>
        </tr>
    </tbody>
</table>

The name of model is: selectedAll

I have two functions, first one should be use for select all and deselect:

isSelectAll() {
    let self = this;
    self.model.selectedLabelList = [];
    if(self.selectedAll) {
        self.selectedAll = true;
        for(var i=0; i < self.formData.battery.testDefinitions.length; i++) {
            self.model.selectedLabelList.push(self.formData.battery.testDefinitions[i].name);       
        }
    }
    else { 
        self.selectedAll = false; 
    }
    angular.forEach(self.formData.battery.testDefinitions, function(item) {
        item.selected = self.selectedAll;
    });
}

And the other one for un-checking 'select all' checkbox if one of the check boxes is deselected manual are this:

isLabelChecked() {
    let self = this;
    let _name = this.formData.battery.name;
    if(this.formData.battery.selected) {
        self.model.selectedLabelList.push(_name);
        if(self.model.selectedLabelList.length == self.labelList.length ) {
            self.selectedAll = true;
        }
    }else{
        self.selectedAll = false;
        let index = self.model.selectedLabelList.indexOf(_name);
        self.model.selectedLabelList.splice(index, 1);
    }
}  

The problem is when defining selectedAll in js file.

I have constructor and if I do not define anything in it, selectedAll won't be in scope.

If I do this:

class NewTestSessionController {
    constructor($scope, $state, resources, NewTestSessionService, formats, AuthenticationService, toastr, momentTimezone, _) {
        this.model = {
            selectedLabelList : []
        };

        this.selectedAll;
}

selectedAll will be in scope, but I will get 'false' value always. No matter if I have selected or deselected checkbox. If I assign some value like this this.selectedAll = true it won't be working correctly of course.

I have problem understanding why ng-model="selectedAll" is not visible and how can I make it visible in js file, without using $scope, since the main goal of my practice is to avoid usage of it.

Can someone see where I am making a mistake?

Upvotes: 3

Views: 1597

Answers (3)

Samudrala Ramu
Samudrala Ramu

Reputation: 2106

var myapp = angular.module('sampleapp', []);

myapp.controller('samplecontoller', function ($scope) {
    $scope.labelList = [
	            { name: 'India' },
	            { name: 'USA' },
	            { name: 'Russia' },
	            { name: 'China' },
	            { name: 'Australia' },
	            { name: 'Japan' }
    ]
    $scope.model = {
        selectedLabelList: []
    }
    $scope.isSelectAll = function () {
        $scope.model.selectedLabelList = [];
        if ($scope.master) {
            $scope.master = true;
            for (var i = 0; i < $scope.labelList.length; i++) {
                $scope.model.selectedLabelList.push($scope.labelList[i].name);
            }
        }
        else { $scope.master = false; }
        angular.forEach($scope.labelList, function (item) {
            item.selected = $scope.master;
        });
    }

    $scope.isLabelChecked = function () {
        var _name = this.label.name;
        if (this.label.selected) {
            $scope.model.selectedLabelList.push(_name);
            if ($scope.model.selectedLabelList.length == $scope.labelList.length) { $scope.master = true; }
        } else {
            $scope.master = false;
            var index = $scope.model.selectedLabelList.indexOf(_name);
            $scope.model.selectedLabelList.splice(index, 1);
        }

    }
});

 
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="sampleapp" ng-controller="samplecontoller">
<input type="checkbox" ng-model="master" ng-change="isSelectAll()"><label>All Countries</label><br>
<li ng-repeat="label in labelList">
<input type="checkbox" ng-model="label.selected" ng-change="isLabelChecked()">
<label>{{ label.name }}</label>
</li>
 </div>

This is example just fallow this code .

Upvotes: 2

Om Shankar
Om Shankar

Reputation: 283

Click here for best solution.

http://jsfiddle.net/TKVH6/2672/

HTML

<div ng-controller="checkboxController">
Check All
<input type="checkbox" ng-model="selectedAll" ng-click="checkAll()" />
<ul>        
  <li ng-repeat="item in Items">
    <label>{{item.Name}}
      <input type="checkbox" ng-model="item.Selected" />
    </label>
  </li>
</ul>
</div>

Script

angular.module("CheckAllModule", [])
    .controller("checkboxController", function checkboxController($scope) {
    $scope.Items = [{
        Name: "Item one"
    }, {
        Name: "Item two"
    }, {
        Name: "Item three"
    }];
    $scope.checkAll = function () {
        if ($scope.selectedAll) {
            $scope.selectedAll = true;
        } else {
            $scope.selectedAll = false;
        }
        angular.forEach($scope.Items, function (item) {
            item.Selected = $scope.selectedAll;
        });
    };
});

Upvotes: 2

Pierre
Pierre

Reputation: 1343

This is a common problem with AngularJS which uses prototypal inheritance between scopes. ng-if directive creates a new scope (call it $scope2) that inherit your controller's $scope. In this new scope you can access selectedAll, but if you assign it (the ng-model directive does), the new value will be set on $scope2, and so $scope2.selectedAll will hide $scope.selectedAll.

Moreover, this.selectedAll; has strictly no effect, you have to assign it to define the property.

To avoid these two issues, put selectedAll in an object, and assign it, like this:

this.model.selectedAll = null; and ng-model="model.selectedAll"

Explanation

The reason why putting it in an object works is because assigning $scope2.model.selectedAll will make JS resolve $scope2.model, which refers to $scope.model because $scope2 has no model property (prototypal inheritance), and then define property selectedAll on that $scope.model.

When you do a.b.c.d = x JS resolves a.b.c object, and then assign x to the property d of that object.

Whithout model, $scope2.selectedAll = true defines the selectedAll property on $scope2, which hides the former $scope.selectedAll.

Upvotes: 2

Related Questions