2017-07-15 65 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以來,已經有了大量的改進。使用一個只有當我告訴它時纔會執行的函數(它會生成一個過濾的數組),在任何方面都會更好,而且這是我將來要做的。