2017-07-15 6 views
0

背景情報角度1.xのフィルター - フィルター要素を変形し、元の配列に影響を及ぼし

ツアー代理店は毎日出発のツアーがあります。これらのツアーのそれぞれには、グループの様々な量があります。同じツアー出発の異なる車両は、同じ日に同時に実行されます。

1)フィルタリング日間のチェックボックスのいずれかが選択されている場合(月、火、水:私は2つのことを行うことができ、フィルタを構築しています、予定されているすべてのツアーを一覧表示管理システムの

など)、選択した日に実行されるツアーのみが表示されます。

2)グループをフィルタリングするためのチェックボックス(第1グループ、第2グループ、第3グループなど)がチェックされている場合、それらのグループのみが表示されます。たとえば、ツアーに1つのグループのみがあり、2番目のグループのチェックボックスがオンの場合、このグループは表示されません。ツアーに3つのグループがあり、2番目のグループの同じチェックボックスがオンになっている場合、2番目のグループだけが表示されます。

問題

日フィルタ部分は完全に正常に動作します。フィルタのグループ順序部分はありません。フィルタでは、配列filteredDepartures内のgroupsオブジェクトからグループを削除すると、元のdepartures配列に影響します。最初のグループ順序フィルタチェックボックスを選択すると、最初のグループを除くすべてのグループが消えますが、同じチェックボックスの選択を解除すると、元のdepartures配列から効果的に削除されたため、グループは再表示されません。

はここに私のフィルタコードです:

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

I:それはfilteredDepartures配列からグループを削除し、だけでなくので、だから、この部分は問題が、ある

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; 
     } 
    }; 
}); 

departures配列から、また、departures配列をJSONで試してみた後、フィルタにすべての新しいオブジェクトを作成して元の配列への参照を削除しましたが、Angularはサイクル数が多すぎるというエラーメッセージを表示します。

EDIT

だけでなくHTMLを投稿。最初の表は、日付の選択、および日やグループのフィルタリング(サイズ・タイプのフィルタリングはまだアクティブではない)です。 2番目の表はツアー出発リストを生成するためのテーブルです。

<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でfilterを使用しないでください。何度も何度も呼び出します。できるだけディレクティブを使用してください。ディレクティブが最も安いためです。あなたはjavascriptオブジェクトのクローンを作成したい場合は

第二に、あなたは元のアイテムをプッシュしているfilteredDepartures.push(departures[i])angular.copyを使用する必要があり、それが複製されていません。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; 
       } 
      } 

     } 
    }; 
}); 

ディレクティブ

<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> 

編集フィルタ用のHTML角度の汚れたフィルターのチェックを回避するためのメフメットOtkunの指導に

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で新しいオブジェクトを作成して解析するときと同じエラーが表示されます(https://docs.angularjs.org/error/$rootScope/infdig)。私は 'filtersDepartures.push(angular.copy(departures [i]));'行でそれを試してみました。それでも同じエラー。すべての手がかりは? –

+1

あなたのHTMLを投稿できますか? –

+0

また、なぜアレイからグルーブを削除しようとしていますか? ng-ifまたはng-hideディレクティブを使用して、チェックボックスまたはグループを表示または非表示にしてください。保存時やバックエンド時に結果をフィルタリングできます。 –

0

おかげで、私は機能$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のバグだということです。 Angular 1.x以来、膨大な量の改善が行われています。フィルタリングされた配列を生成する、私がそれを指示するときに実行される関数を使うことは、どんな方法でも優れており、将来私がやることは間違いありません。

関連する問題