Angular JS splice function not removing existing field in array

Tags: ,



I am trying to use the splice() function in Angular JS. I have a dropdown from which users can select an item.

The selected item has a field and a value which gets parsed into the array ‘criteria’.

The user then clicks another item on the same drop down, and I want to make sure it checks to see if the field already exists. If it does, the code should remove the existing field and insert the new one.

There should only ever be one field name in this array.

Please note I have other drop down lists using the same criteria array so these should not be effected.

Example drop down list contains:

0 *
1 Apple
2 Pear
3 Orange

Currently if you click Apple, the criteria array populates correctly.

Field: TypeName, Value: Apple

The second time you click on the SAME drop down, the Orange criteria array populates as follows:

Field: TypeName, Value: Apple
Field: TypeName, Value: Orange

I need the code to remove the original click item, as the field TypeName already exists in the array; e.g. the value Apple and Push/Replace with Orange into the criteria array

HTML – example drop down code that calls ng-click filterData function:

<span class="input-group-btn">
  <div class="dropdown">
    <button class="btn btn-error dropdown-toggle" type="button" data-toggle="dropdown" ng-bind="selected">
      Select Type
      <span class="caret"></span>
    </button>
    <ul class="dropdown-menu">
      <li class="list-group-item-{{item.type}}" ng-repeat="item in types">
        <a href="#" ng-click="filterData('TypeName',item.type); setType(item.type)">{{item.type}}</a >
      </li>
    </ul>
  </div>
</span>  
Array.prototype.flexFilter = function(info) {
      
      // Set our variables
      var matchesFilter, matches = [], count;
      
      // Helper function to loop through the filter criteria to find matching values
      // Each filter criteria is treated as "AND". So each item must match all the filter criteria to be considered a match.
      // Multiple filter values in a filter field are treated as "OR" i.e. ["Blue", "Green"] will yield items matching a value of Blue OR Green.
      matchesFilter = function(item) {
        count = 0
        for (var n = 0; n < info.length; n++) {
          if (info[n]["Values"].indexOf(item[info[n]["Field"]]) > -1) {
            count++;
          }
        }
        // If TRUE, then the current item in the array meets all the filter criteria
        return count == info.length;
      }
    

console.log("length ", this.length);
      // Loop through each item in the array
      for (var i = 0; i < this.length; i++) {
        // Determine if the current item matches the filter criteria
        if (matchesFilter(this[i])) {
          matches.push(this[i]);
        }
      }
     

console.log("matches log ", matches); 

      // Give us a new array containing the objects matching the filter criteria
      return matches;
    }
      //Add this next to your functions
var criteria = [];


$scope.filterData = function filterData(field, value) {

  var index = criteria.map(function(e) { return e.field; }).indexOf(field);
  console.log(index);
  if (index > -1 || value == "*")  //ISSUE IS HERE
  {
    criteria.splice(index, 1);
  } 
  else 
  {
    criteria.push({ Field:field, Values: [value] });
    console.log(criteria);
  }
let newData = $scope.dummyData.flexFilter(criteria);
$scope.getData(newData);
}

The first time I click the item my index is -1.
The second time I click an item my index seems to still be -1.

Console log output:

(2) [{…}, {…}]
0: {Field: "TypeName", Values: Array(1)}
1: {Field: "TypeName", Values: Array(1)}
length: 2

Answer

The question is not very clear but looking at your expected output I think the mistake is in line

var index = criteria.map(function(e) { return e.field; }).indexOf(field);

e.field should be e.Field. So, correct statement is:

var index = criteria.map(function(e) { return e.Field; }).indexOf(field);

further do not push to criteria inside else. Based on your expected output you always want to push. You just want to remove if anything is already there before pushing.

     $scope.filterData = function filterData(field, value) {
       
        var index = criteria.map(function (e) {
            return e.Field;
        }).indexOf(field)
        console.log(index);
        if (index > -1 || value == "*")  //ISSUE IS HERE
        {
            criteria.splice(index, 1);
        }
        criteria.push({ Field: field, Values: [value] });
        console.log(criteria);
        let newData = $scope.dummyData.flexFilter(criteria);
        $scope.getData(newData);
    }


Source: stackoverflow