Nick
Nick

Reputation: 14283

indexof - check if a value is already in array with javascript)

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

Upvotes: 2

Views: 114

Answers (2)

Nick
Nick

Reputation: 14283

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!

Upvotes: 1

Matthias
Matthias

Reputation: 3900

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.

Upvotes: 0

Related Questions