2017-07-15 55 views
0

背景信息角1.x的过滤器 - 修改过滤元素影响原数组

旅游咨询机构有旅行团每天出发。在每个巡回赛中都有不同数量的团体 - 同一天的同一天巡回赛同一时间不同的车辆。

对于管理系统,列出了所有预定之旅,我建立一个过滤器,可以做两件事情:

1)如果任何复选框过滤天的选择(周一,周二,周三等等),只有在选定日期上运行的巡回路线才会显示。 2)如果选中过滤组(第一组,第二组,第三组等)的任意复选框,则只显示这些组。例如:如果游览只有一个组,并且选中了第二组的复选框,则该组不会显示。如果一个游览有三个组,并且选中了与第二组相同的复选框,则只会显示第二个组。

问题

一天滤波部分工作完全正常。过滤器的组顺序部分没有。在过滤器中,每当我从filteredDepartures阵列中的groups对象中删除组时,它都会影响原始的departures阵列。每当我选择第一个组排序过滤器复选框时,除第一个组以外的所有组都消失,但是当我取消选择相同的复选框时,这些组不会再出现,因为它们已从原始departures阵列中有效地移除。

这里是我的过滤代码:

app.filter('departuresFilter', function() { //Filter departures 
    return function(departures, filterOptions) { 

     if (typeof departures !== 'undefined') //If there are departures 
     { 
      var filteredDepartures = []; //Create new array 

      //See if days should be filtered 
      filterOptions.daysFiltered = false; //Assuming days won't be filtered 
      filterOptions.days.forEach(function(day) { 
       if (day.selected) //Day is selected 
        filterOptions.daysFiltered = true; 
      }); 

      //See if group orders should be filtered 
      //The array groupsInDepartures is an array that has as many elements as the highest amount of groups on any day within selected date range (typically 1-3 elements) 
      filterOptions.groupOrdersFiltered = false; //Assuming group orders won't be filtered 
      filterOptions.groupsInDepartures.groups.forEach(function (group) { //For every group order. 
       if (group.selected) //A checkbox has been selected 
        filterOptions.groupOrdersFiltered = true; 
      }); 

      for (i = 0; i < departures.length; i++) //For every tour departure 
      { 
       var removeDeparture = false; //Assuming departure will not be removed 

       if (filterOptions.daysFiltered) //Days are filtered 
       { 
        filterOptions.days.forEach(function(day) { //For every day in filter array 
         if (day.title == departures[i].date.D) //Found this group's day in day filter array 
         { 
          if (day.selected == false) //This day is not selected (should not show) 
           removeDeparture = true; //Remove day 
         } 
        }); 
       } 

       //Departure is not to be removed - check if any groups should be removed 
       if (removeDeparture == false) 
       { 
        filteredDepartures.push(departures[i]); //Add departure to filtered departures array 

        if (filterOptions.groupOrdersFiltered) //Group orders should be filtered. Only show groups of which their corresponding checkbox has been selected. 
        { 
         var departureIndex = filteredDepartures.length - 1; //Get index for last departure 

         for (j = filteredDepartures[departureIndex].groups.length; j > 0; j--) //For every group in departure. Start from above, to not mess up indexes. 
         { 
          if (!filterOptions.groupsInDepartures.groups[j - 1].selected) //This group should be removed 
           filteredDepartures[departureIndex].groups.splice((j - 1), 1); //Remove group 
         } 
        } 
       } 
      } 

      return filteredDepartures; 
     } 
    }; 
}); 

因此,这部分是问题,因为它不仅从filteredDepartures删除数组组,而且从departures阵列:

if (!filterOptions.groupsInDepartures.groups[j - 1].selected) //This group should be removed 
    filteredDepartures[departureIndex].groups.splice((j - 1), 1); //Remove group 

我我也尝试过使用JSON来刺激departures数组,然后在过滤器中创建一个全新的对象,以删除对原始数组的任何引用,但是Angular向我提供了有关太多循环的错误消息。

编辑

发布HTML以及。第一个表格用于选择日期,并用于过滤日期和组(大小类型过滤尚未激活)。第二个表格用于生成旅行离境列表。

<table style="margin: 40px 0;"> 
    <tr> 
     <td> 
      <h2>Dates</h2> 
     </td> 
     <td style="padding-left: 40px;"> 
      <h2>Filter groups</h2> 
     </td> 
     <td style="padding-left: 40px;"> 
      <h2>Filters applied</h2> 
     </td> 
    </tr> 
    <tr> 
     <td style="vertical-align: top;"> 
      <ul class="cleanList"> 
       <li>From <input type="text" class="form-control" ng-model="dateStart" style="width: 120px; text-align: center;" ng-change="loadGroups()" jqdatepicker></li> 
       <li>To<input type="text" class="form-control" ng-model="dateEnd" style="width: 120px; text-align: center;" ng-change="loadGroups()" jqdatepicker></li> 
      </ul> 
     </td> 
     <td style="padding-left: 40px; vertical-align: top;"> 
      Size Type 
      <select class="form-control" ng-model="filterOptions.sizeType"> 
       <option></option> 
       <option ng-repeat="sizeType in groupSizeTypes" value="{{ sizeType.id }}">{{ sizeType.title }}</option> 
      </select> 

      <ul class="horList"> 
       <li ng-repeat="day in filterOptions.days"> 
        <div><label for="{{ day.title }}">{{ day.title }}</label></div> 
        <div style="text-align: center;"><input type="checkbox" id="{{ day.title }}" ng-model="day.selected"></div> 
       </li> 
      </ul> 

      <div ng-show="filterOptions.groupsInDepartures.groups.length > 0"> 
       Groups 
       <ul class="horList"> 
        <li ng-repeat="group in filterOptions.groupsInDepartures.groups"> 
         <div><label for="nth_group_{{ group.order }}">{{ group.order }}</label></div> 
         <div style="text-align: center;"><input type="checkbox" id="nth_group_{{ group.order }}" ng-model="group.selected"></div> 
        </li> 
       </ul> 
      </div> 
     </td> 
     <td style="padding-left: 40px; vertical-align: top;" ng-show="filterOptions.tag != '' || filterOptions.daysFiltered || filterOptions.groupOrdersFiltered"> 
      <ul> 
       <li ng-show="filterOptions.tag != ''">Tag</li> 
       <li ng-show="filterOptions.daysFiltered">Days</li> 
       <li ng-show="filterOptions.groupOrdersFiltered">Groups</li> 
      </ul> 
     </td> 
    </tr> 
</table> 

{{ departures }} <!-- for debugging (filtering groups from filteredDepartures removes them from this array as well) --> 

<p id="loadWrap" style="display: none;"><span class="loadBox"><img src="/images/misc/ajax-loader.gif">Loading</span></p> 
<p ng-show="filteredDepartures.length" class="small"><i>Showing {{ filteredDepartures.length }} departures.</i></p> 

<table class="table"> 
    <tr> 
     <th>Date</th> 
     <th>Tour</th> 
     <th>Size type</th> 
     <th>Pax</th> 
     <th>Guide</th> 
     <th>Salary K CLP</th> 
     <th>Vehicle</th> 
     <th>Rental K CLP</th> 
    </tr> 
    <tbody ng-repeat="departure in filteredDepartures = (departures | departuresFilter:filterOptions)"> 
     <tr class="danger"> 
      <td><a style="cursor: pointer;" ng-click="loadThisDate(departure.date.Ymd)">{{ departure.date.Mj }}</a><div class="small" style="color: gray;">{{ departure.date.D }}</div></td> 
      <td>{{ departure.tour.title }}</td> 
      <td>{{ departure.tour.sizeType.title }}</td> 
      <td colspan="5"></td> 
     </tr> 
     <tr ng-repeat="group in departure.groups" class="trNoTopBorder danger"> 
      <td colspan="3"></td> 
      <td>{{ group.pax }}/{{ group.capacity }}</td> 
      <td>{{ group.guide.name }}</td> 
      <td>{{ group.salaryKCLP }}</td> 
      <td>{{ group.vehicle.name }}</td> 
      <td>{{ group.vehicleRentalKCLP }}</td> 
     </tr> 
    </tbody> 
</table> 

回答

1

首先,避免在angularjs上使用过滤器,因为它会一次又一次地调用。尽可能使用指令,因为指令是最便宜的。

其次,如果你想克隆一个JavaScript对象,你应该使用angular.copyfilteredDepartures.push(departures[i])你推原始项目,它不是克隆。使用filteredDepartures.push(angular.copy(departures[i]));

另外,如果filterOptions是静态的,即不可变更,则可以仅监视$;

app.directive('departuresDirective', function() { 
    return { 
     restrict: 'AC', 
     link: function (scope, element, attr, ngModel) { 
      var filterOptions, departures; 
      scope.filteredDepartures = []; 
      scope.$watchGroup([attr.filterOptions, attr.departures], function (newValues, oldValues, scope) { 
       filterOptions = newValues[0]; 
       departures = newValues[1]; 
       scope.filteredDepartures = filterDepartures(departures, filterOptions); 
      }, true); 

      function filterDepartures(departures, filterOptions) { 
       if (typeof departures !== 'undefined') //If there are departures 
       { 
        var filteredDepartures = []; //Create new array 

        //See if days should be filtered 
        filterOptions.daysFiltered = false; //Assuming days won't be filtered 
        filterOptions.days.forEach(function (day) { 
         if (day.selected) //Day is selected 
          filterOptions.daysFiltered = true; 
        }); 

        //See if group orders should be filtered 
        //The array groupsInDepartures is an array that has as many elements as the highest amount of groups on any day within selected date range (typically 1-3 elements) 
        filterOptions.groupOrdersFiltered = false; //Assuming group orders won't be filtered 
        filterOptions.groupsInDepartures.groups.forEach(function (group) { //For every group order. 
         if (group.selected) //A checkbox has been selected 
          filterOptions.groupOrdersFiltered = true; 
        }); 

        for (i = 0; i < departures.length; i++) //For every tour departure 
        { 
         var removeDeparture = false; //Assuming departure will not be removed 

         if (filterOptions.daysFiltered) //Days are filtered 
         { 
          filterOptions.days.forEach(function (day) { //For every day in filter array 
           if (day.title == departures[i].date.D) //Found this group's day in day filter array 
           { 
            if (day.selected == false) //This day is not selected (should not show) 
             removeDeparture = true; //Remove day 
           } 
          }); 
         } 

         //Departure is not to be removed - check if any groups should be removed 
         if (removeDeparture == false) { 
          filteredDepartures.push(angular.copy(departures[i])); //Add departure to filtered departures array 

          if (filterOptions.groupOrdersFiltered) //Group orders should be filtered. Only show groups of which their corresponding checkbox has been selected. 
          { 
           var departureIndex = filteredDepartures.length - 1; //Get index for last departure 

           for (j = filteredDepartures[departureIndex].groups.length; j >= 0; j--) //For every group in departure. Start from above, to not mess up indexes. 
           { 
            if (!filterOptions.groupsInDepartures.groups[j - 1].selected) //This group should be removed 
             filteredDepartures[departureIndex].groups.splice((j - 1), 1); //Remove group 
           } 
          } 
         } 
        } 

        return filteredDepartures; 
       } 
      } 

     } 
    }; 
}); 

的HTML指令

<table class="table" departures-directive="" departures="departures" filter-options="filterOptions"> 
    <tr> 
     <th>Date</th> 
     <th>Tour</th> 
     <th>Size type</th> 
     <th>Pax</th> 
     <th>Guide</th> 
     <th>Salary K CLP</th> 
     <th>Vehicle</th> 
     <th>Rental K CLP</th> 
    </tr> 
    <tbody ng-repeat="departure in filteredDepartures track by $index"> 
     <tr class="danger"> 
      <td><a style="cursor: pointer;" ng-click="loadThisDate(departure.date.Ymd)">{{ departure.date.Mj }}</a><div class="small" style="color: gray;">{{ departure.date.D }}</div></td> 
      <td>{{ departure.tour.title }}</td> 
      <td>{{ departure.tour.sizeType.title }}</td> 
      <td colspan="5"></td> 
     </tr> 
     <tr ng-repeat="group in departure.groups track by $index" class="trNoTopBorder danger"> 
      <td colspan="3"></td> 
      <td>{{ group.pax }}/{{ group.capacity }}</td> 
      <td>{{ group.guide.name }}</td> 
      <td>{{ group.salaryKCLP }}</td> 
      <td>{{ group.vehicle.name }}</td> 
      <td>{{ group.vehicleRentalKCLP }}</td> 
     </tr> 
    </tbody> 
</table> 

编辑过滤

app.filter('departuresFilter', function() { //Filter departures 
    return function(_departures, _filterOptions) { 
     var departures = angular.copy(_departures); 
     var filterOptions = angular.copy(_filterOptions); 
     if (typeof departures !== 'undefined') //If there are departures 
     { 
      var filteredDepartures = []; //Create new array 

      //See if days should be filtered 
      filterOptions.daysFiltered = false; //Assuming days won't be filtered 
      filterOptions.days.forEach(function(day) { 
       if (day.selected) //Day is selected 
        filterOptions.daysFiltered = true; 
      }); 

      //See if group orders should be filtered 
      //The array groupsInDepartures is an array that has as many elements as the highest amount of groups on any day within selected date range (typically 1-3 elements) 
      filterOptions.groupOrdersFiltered = false; //Assuming group orders won't be filtered 
      filterOptions.groupsInDepartures.groups.forEach(function (group) { //For every group order. 
       if (group.selected) //A checkbox has been selected 
        filterOptions.groupOrdersFiltered = true; 
      }); 

      for (i = 0; i < departures.length; i++) //For every tour departure 
      { 
       var removeDeparture = false; //Assuming departure will not be removed 

       if (filterOptions.daysFiltered) //Days are filtered 
       { 
        filterOptions.days.forEach(function(day) { //For every day in filter array 
         if (day.title == departures[i].date.D) //Found this group's day in day filter array 
         { 
          if (day.selected == false) //This day is not selected (should not show) 
           removeDeparture = true; //Remove day 
         } 
        }); 
       } 

       //Departure is not to be removed - check if any groups should be removed 
       if (removeDeparture == false) 
       { 
        filteredDepartures.push(departures[i]); //Add departure to filtered departures array 

        if (filterOptions.groupOrdersFiltered) //Group orders should be filtered. Only show groups of which their corresponding checkbox has been selected. 
        { 
         var departureIndex = filteredDepartures.length - 1; //Get index for last departure 

         for (j = filteredDepartures[departureIndex].groups.length; j >= 0; j--) //For every group in departure. Start from above, to not mess up indexes. 
         { 
          if (!filterOptions.groupsInDepartures.groups[j - 1].selected) //This group should be removed 
           filteredDepartures[departureIndex].groups.splice((j - 1), 1); //Remove group 
         } 
        } 
       } 
      } 

      return filteredDepartures; 
     } 
    }; 
}); 
+0

非常感谢您的详细回答,我会查看指令!我不知道如何在HTML中使用它们,但我会查找它。当我使用angular.copy时,得到与使用JSON stringify和parse创建新对象时相同的错误:https://docs.angularjs.org/error/$rootScope/infdig。我在线'filteredDepartures.push(angular.copy(departures [i]));'以及整个数组的开头拷贝整个数组。还是一样的错误。任何线索? –

+1

你能发布你的HTML吗? –

+0

也为什么你试图从数组中删除gruop?只需使用ng-if或ng-hide指令来显示或隐藏复选框或组。您可以在保存时或后端过滤结果。 –

0

感谢穆罕默德Otkun的指导,避免角的脏的过滤器的检查,最后我写一个函数$scope.filterDepartures()。在每个选择框和复选框中,我添加了一个ng-change="filterDepartures()"。该函数的代码基本上完全相同。这个版本稍微长一点,因为我在白天一直在开发更多的版本。尽管如此,一个基本的细节是使用angular.copy()来丢失对原始对象的所有引用。

这里的功能:

$scope.filterDepartures = function() { //Filter departures 
    $scope.filteredDepartures = []; //Create new array 
    $scope.groupCount = 0; //Reset group count var 
    $scope.filterOptions.largestGroup = 0; //Var for remembering biggest group. This is for creating capacity array for editing groups. 

    //See if days should be filtered 
    $scope.filterOptions.daysFiltered = false; //Assuming days won't be filtered 
    $scope.filterOptions.days.forEach(function(day) { 
     if (day.selected) //Day is selected 
      $scope.filterOptions.daysFiltered = true; 
    }); 

    //See if group orders should be filtered 
    //The array groupsInDepartures is an array that has as many elements as the highest amount of groups on any day within selected date range (typically 1-3 elements) 
    $scope.filterOptions.groupOrdersFiltered = false; //Assuming group orders won't be filtered 
    $scope.filterOptions.groupsInDepartures.groups.forEach(function (group) { //For every group order. 
     if (group.selected) //A checkbox has been selected 
      $scope.filterOptions.groupOrdersFiltered = true; 
    }); 

    for (i = 0; i < $scope.departures.length; i++) //For every tour departure 
    { 
     var removeDeparture = false; //Assuming departure will not be removed 

     if ($scope.filterOptions.daysFiltered) //Days are filtered 
     { 
      $scope.filterOptions.days.forEach(function(day) { //For every day in filter array 
       if (day.title == $scope.departures[i].date.D) //Found this group's day in day filter array 
       { 
        if (day.selected == false) //This day is not selected (should not show) 
         removeDeparture = true; //Remove day 
       } 
      }); 
     } 

     //Departure is not to be removed - check if any groups should be removed 
     if (removeDeparture == false) 
     { 
      var tempDeparture = angular.copy($scope.departures[i]); //Create temporary departure object 

      for (j = (tempDeparture.groups.length - 1); j >= 0; j--) //For every group in departure. Start from above, to not mess up indexes. 
      { 
       var removeGroup = false; //Assuming group shouldn't be removed 

       if ($scope.filterOptions.groupOrdersFiltered && !$scope.filterOptions.groupsInDepartures.groups[j].selected) //Group orders should be filtered. Only show groups of which their corresponding checkbox has been selected. 
        removeGroup = true; //Remove group later 
       else //Continue checking 
       { 
        //Check if guide is filtered, and if this group has the correct guide 
        if ($scope.filterOptions.guide.exists && $scope.filterOptions.guide.id != tempDeparture.groups[j].guide.id) 
         removeGroup = true; 
        else //Guide was not filtered. Continue checking 
        { 
         //Check if vehicle is filtered, and if this group has the correct vehicle 
         if ($scope.filterOptions.vehicle.exists && $scope.filterOptions.vehicle.id != tempDeparture.groups[j].vehicle.id) 
          removeGroup = true; 
        } 
       } 


       if (removeGroup) //Group should be removed 
        tempDeparture.groups.splice((j), 1); //Remove group 
      } 

      //Loop through all groups that are left, looking for largest group 
      tempDeparture.groups.forEach(function (group) { 
       if (group.pax > $scope.filterOptions.largestGroup) //Found bigger group 
        $scope.filterOptions.largestGroup = group.pax; //Save to var 
      }); 

      $scope.groupCount += tempDeparture.groups.length; 

      if (!$scope.filterOptions.hideGrouplessDepartures || $scope.filterOptions.hideGrouplessDepartures && tempDeparture.groups.length > 0) 
       $scope.filteredDepartures.push(tempDeparture); //Add departure to filtered departures array 
     } 
    } 

    $scope.capEditGroupsOptions = []; 
    //Renew array for editing group capacity, to let user limit capacity to the same amount of pax as the most amount of pax in any of the groups that are shown 
    for (i = $scope.filterOptions.largestGroup; i <= <?php echo $maxCapacity; ?>; i++) //For every capacity option possible 
    { 
     $scope.capEditGroupsOptions.push(i); 
    } 
}; 

我仍然不知道为什么它不使用过滤器的工作。我唯一的想法就是它是Angular中的一个bug。自Angular 1.x以来,已经有了大量的改进。使用一个只有当我告诉它时才会执行的函数(它会生成一个过滤的数组),在任何方面都会更好,而且这是我将来要做的。