简体   繁体   中英

Checkbox in AngularJS “double checking” after click

I'm trying to make a simple to do list app using Angular. When the user clicks the checkbox, the list item should disappear. Right now, the list item disappears upon clicking the checkbox, but the checkbox of the list item directly below it also gets checked (although the list item doesn't disappear).

<ul ng-repeat="item in arr track by $index">
    <li>
        <input type="checkbox" ng-click="check(item)">
        <span>{{ item }}</span>
    </li>
</ul>

$scope.arr = [
    'todo 1',
    'todo 2',
    'todo 3'
];

$scope.check = function(item) {
    var indexOf = $scope.arr.indexOf(item);
    if (indexOf !== -1) {
        $scope.arr.splice(indexOf, 1);
    }
};

Is there any way to solve this?

The checkbox directly under the deleted item was automatically being checked because the information, that first the element in array is checked was still valid, but the length of the array reduces with every splice method executed. That's why you have to actually tell angular that check another element, which takes index: 0 in the array after previous element gets spliced is unnecessary .

Here's the solution: Plunker link

Raw code:

<ul ng-repeat="item in arr track by $index">
  <li>
    <input type="checkbox" ng-click="check(item)" ng-model="item.selected">
    <span>{{ item }}</span>
  </li>
</ul>


$scope.arr = [
  'todo 1',
  'todo 2',
  'todo 3'
];

$scope.check = function(item) {
  var indexOf = $scope.arr.indexOf(item);
  if (indexOf !== -1) {
    $scope.arr.splice(indexOf, 1);
    $scope.item.selected = false;
}

Not sure how this is working as-is, but the normal way to accomplish this is with an ng-model on the <input> . Make your items into objects so they can store more complex state, which also lets you drop track by .

<ul ng-repeat="item in arr">
  <li>
    <input type="checkbox" ng-model="item.done">
    <span>{{item.label}}</span>
  </li>
</ul>

$scope.arr = [
  {label: 'todo 1', done: false},
  {label: 'todo 2', done: false},
  {label: 'todo 3', done: false}
];

That should get your checking and unchecking set up correctly. To drop items when they're done, I recommend a filer on the ng-repeat .

ng-repeat="item in arr | filter: {done: 'false'}"

https://plnkr.co/edit/ybikvwysC6ZEd7CeZnnt?p=preview

That happens because you use "track by $index". Try without track by, or use track by with some unique field (id), in which case your list should consist of objects, not primitives. For example:

$scope.arr = [
  {id: 1, name: 'todo 1'},
  {id: 2, name: 'todo 2'},
  {id: 3, name: 'todo 3'} //...
];

<ul ng-repeat="item in arr track by item.id">
    <li>
        <input type="checkbox" ng-click="check($index)">
        <span>{{item.name}}</span>
    </li>
</ul>

$scope.check = function(index) {
    $scope.arr.splice(index, 1);
}

You need to prevent the click event from performing the default action

 <input type="checkbox" ng-click="check(item);$event.preventDefault();" />

Angular is removing the element, on the click, but then the (moved) element also gets the click event, checking it. $event.preventDefault() will prevent this.

Here is a working plunk

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM