背景信息
旅行社每天都有出发的旅行团。在这些旅行中,每个旅行团都有不同的数量 - 同一天同一个旅游出发的不同车辆同时运行。
对于列出所有已安排的游览的管理系统,我构建了一个可以做两件事的过滤器:
1)如果选择过滤天数的任何复选框(周一,周二,周三等),则只显示在这些选定日期运行的游览。
2)如果选中过滤组(第一组,第二组,第三组等)的任何复选框,则仅显示那些组。例如:如果巡视只有一个组并且选中了第二组的复选框,则该组将不会显示。如果一个巡视有三个组,并且选中了同一个第二组的复选框,那么只会显示第二个组。
问题
日间过滤器部分完美无缺。过滤器的组订单部分没有。在过滤器中,每当我从groups
数组中的filteredDepartures
对象中删除组时,它都会影响原始的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-stingifying 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>
答案 0 :(得分:1)
首先,避免在angularjs上使用过滤器,因为它会一次又一次地调用。尽可能使用指令,因为指令是最便宜的。
其次,如果你想要克隆一个javascript对象,你应该使用 angular.copy 在 filteredDepartures.push(departures[i])
上你是推送原始项目,它不会被克隆。使用filteredDepartures.push(angular.copy(departures[i]));
此外,如果filterOptions是静态的,即不是changaable,你可以只观看离开;
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>
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;
}
};
});
答案 1 :(得分:0)
感谢Mehmet Otkun的指导,为了避免Angular的脏过滤检查,我最终编写了一个函数$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以来,已经有了大量的改进。使用仅在我告诉它时执行的函数(生成过滤后的数组)在任何情况下都会更好,并且肯定是我将来要做的事情。