2

I am working with angular and I am trying to create a "select all" button.

I have a list of items, each item has a toggle and what I am doing is, on change (everytime the toggle changes from true (selected) to false (not selected), I run a function to create an array with all the IDs of the selected elements.

This works almost perfectly, the problem is that I am facing some issues with the indexfOf method to check if the ID is already in the array.

var isInArray;

isInArray = function(arr, id) {
  console.log("index of ", arr.indexOf(id));
  return arr.indexOf(id);
};


scope.evtSelectAll = function() {
  return angular.forEach(scope.listToDisplay, function(element) {
    element.copyTo = true;
    return scope.selectFromList(element.iID, element.copyTo);
  });
};

scope.selectFromList = function(id, copy) {
  if (copy === true && isInArray(scope.selected, id) === -1) {
    scope.selected.push(id);
  } else {
    scope.selected.pop(id);
  }
  console.log("scope.selected - ", scope.selected);
  if (scope.selected.length > 0) {
    console.log("Emitted event: can proceed!");
    scope.$emit('enough-elements');
  } else {
    console.log("Emitted event: can not proceed!");
    scope.$emit('not-enough-elements');
  }
  return scope.result = scope.selected;
};

the problem I've got is when the array (scope.selected) has multiple IDs.

Let's say, for example, that my scope.selected looks like this:

scope.selected = [2,3,4,7]

if I click on select all, nothing gets added (and this is correct)

Now, let's say I untick 4 and 7 for example, and my scope.selected now looks like this:

scope.selected = [2,3]

If I now click on select all, my result is the following: [2,4,7].

I lose the 3

I think this is due to the fact that my array doesn't have one single item?

thanks for any help. Here's also a quick codepen to explain the problem. If you check the console and play with the toggles you should be able to see straight away what I am referring to.

Thanks in advance

4
  • 2
    Would it be an issue to empty $scope.selected entirely and recreate it by reparsing the checked elements in the list, once a toggle has occured? Commented Nov 28, 2016 at 11:53
  • No I don't see why it should be an issue to be honest. I just need to be careful to empty it only on select all I guess, right? Commented Nov 28, 2016 at 11:54
  • 1
    at least in the codepen example, the element.iID should be changed to element.id Commented Nov 28, 2016 at 12:04
  • thanks, I corrected iID with id Commented Nov 28, 2016 at 12:04

2 Answers 2

1

Thanks to Matthias and Christian Bonato for their suggestions.

At the end, I solved using both of their suggestions and the final result seems to work as expected.

Here's a codepen with the final version: http://codepen.io/NickHG/pen/KNXPBb

Basically, I changed

scope.selected.pop(id);

with

$scope.selected.splice( isInArray($scope.selected, id),1);

and in the selectAll event function, I always empty scope.selected[] before adding elements to the array

$scope.evtSelectAll = function() {
$scope.selected = []
angular.forEach($scope.list, function(element) {
  element.copyTo = true;
  return $scope.selectFromList(element.id, element.copyTo);
});

};

thank you for your help!

Sign up to request clarification or add additional context in comments.

2 Comments

emptying the array seems like a nice solution to the problem here, good work
I can accept only in two days. I will accept as soon as I can. thanks
0

I think mostly your code contains a logical error. You are using the function selectFromList to de-select (when done individually) and for the select all (which you don't want to use to de-select).

As someone pointed out in a for some reason now deleted answer, the pop.() function shouldn't be called with any arguments (it is only for removing the last element), you should use splice like this: $scope.selected.splice( isInArray($scope.selected, id),1);

Unless you really need the emitted functionality to run on a select all, you can try if this is the answer for you:

var isInArray;

isInArray = function(arr, id) {
  console.log("index of ", arr.indexOf(id));
  return arr.indexOf(id);
};


scope.evtSelectAll = function() {
  return angular.forEach(scope.listToDisplay, function(element) {
    element.copyTo = true;
    if (isInArray($scope.selected, element.id) === -1) {
      $scope.selected.push(element.id);
    }
  });
};

scope.selectFromList = function(id, copy) {
  if (copy === true && isInArray(scope.selected, id) === -1) {
    scope.selected.push(id);
  } else {
    $scope.selected.splice(isInArray($scope.selected, id), 1);
  }
  console.log("scope.selected - ", scope.selected);
  if (scope.selected.length > 0) {
    console.log("Emitted event: can proceed!");
    scope.$emit('enough-elements');
  } else {
    console.log("Emitted event: can not proceed!");
    scope.$emit('not-enough-elements');
  }
  return scope.result = scope.selected;
};

Now the select all only adds to scope.selected if it doesn't find the id in the scope.selected list.

1 Comment

Thanks for the answer. I added your line, and I changed the select all function to include the first comment (empty scope.selected when I click on select all) and with the two combined solution, it seam to work as I need. Thanks a lot

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.