根据您的示例应用程序和描述,我将用 Angular 术语描述您的需求:
- 过滤器切换视图的控制器
- 案例视图的控制器
- 存储切换过滤器的服务
- 过滤器切换按钮的指令
- 通过切换过滤器减少案例列表的过滤器
工作示例:JSFiddle (已更新为使用 ngRoute)
控制器
这两个控制器应该作为视图模型,提供一些可以在各自的视图模板中使用的格式良好的数据。例如:
angular.module('myApp')
.controller('FilterToggleController', FilterToggleController)
.controller('CasesController', CasesController)
;
function FilterToggleController() {
var vm = this;
vm.filterGroups = {
1: [1,2],
2: [1,2]
};
}
function CasesController() {
var vm = this;
vm.cases = [
{label:'Case 1,2', filters:[{group:1, filter:1}, {group:1, filter: 2}]},
{label:'Case 1', filters:[{group:1, filter:1}]},
{label:'Case 2', filters:[{group:1, filter:2}]},
{label:'Case 1,3', filters:[{group:1, filter:1}, {group:2, filter:1}]},
{label:'Case 4', filters:[{group:2, filter:2}]}
];
}
服务
Angular 服务的目的是在控制器、指令、过滤器和其他服务之间共享数据或功能。您的服务是所选过滤器的数据存储,因此我将在后台使用$cacheFactory 缓存。例如:
angular.module('myApp')
.factory('$filterCache', filterCacheFactory)
;
function filterCacheFactory($cacheFactory) {
var cache = $cacheFactory('filterCache');
var $filterCache = {};
$filterCache.has = function(group, filter) {
return cache.get(concat(group, filter)) === true;
};
$filterCache.put = function(group, filter) {
cache.put(concat(group, filter), true);
}
$filterCache.remove = function(group, filter) {
cache.remove(concat(group, filter));
}
$filterCache.count = function() {
return cache.info().size;
}
function concat(group, filter) {
return group + ':' + filter;
}
return $filterCache;
}
指令
指令向 HTML 元素添加功能。在您的情况下,我将创建一个带有“click”事件处理程序的指令,该处理程序可以作为属性添加到按钮或任何其他元素。事件处理程序可以使用我们的$filterCache 服务来跟踪按钮所代表的组/过滤器组合。例如:
angular.module('myApp')
.directive('toggleFilter', toggleFilterDirective)
;
function toggleFilterDirective($filterCache) {
return function(scope, iElement, iAttrs) {
var toggled = false;
iElement.on('click', function() {
var group = scope.$eval(iAttrs.group);
var filter = scope.$eval(iAttrs.filter);
toggled = !toggled;
if (toggled) {
$filterCache.put(group, filter);
iElement.addClass('toggled');
} else {
$filterCache.remove(group, filter);
iElement.removeClass('toggled');
}
scope.$apply();
});
};
}
过滤器
过滤器的目的是获取CasesController 中定义的案例对象数组,并根据存储在我们的$filterCache 服务中的过滤器来减少它们。如果没有切换过滤器,它会将列表减少为空数组。例如:
angular.module('myApp')
.filter('filterCases', filterCasesFactory)
;
function filterCasesFactory($filterCache) {
return function(items) {
var filteredItems = [];
var filterCount = $filterCache.count();
if (filterCount) {
angular.forEach(items, function(item) {
if (angular.isArray(item.filters) && item.filters.length >= filterCount) {
for (var matches = 0, i = 0; i < item.filters.length; i++) {
var group = item.filters[i].group;
var filter = item.filters[i].filter;
if ($filterCache.has(group, filter))
matches++;
if (matches === filterCount) {
filteredItems.push(item);
break;
}
}
}
});
}
return filteredItems;
};
}
模板
最后,HTML 模板将它们联系在一起。以下是使用我们构建的所有其他部分的外观示例:
<!-- Filter Toggles View -->
<div ng-controller="FilterToggleController as vm">
<div ng-repeat="(group, filters) in vm.filterGroups">
<h2>
Group {{group}}
</h2>
<div ng-repeat="filter in filters">
<button toggle-filter group="group" filter="filter">
Filter {{filter}}
</button>
</div>
</div>
</div>
<!-- Cases View -->
<div ng-controller="CasesController as vm">
<h2>
Your Cases
</h2>
<ol>
<li ng-repeat="case in vm.cases | filterCases">
{{case.label}}
</li>
</ol>
</div>
更新
基于 cmets,我通过对 toggleFilterDirective 进行以下更改,更新了 JSFiddle 示例以使用 ngRoute:
function toggleFilterDirective($filterCache) {
return function(scope, iElement, iAttrs) {
var group, filter, toggled;
sync();
update();
iElement.on('click', onClick);
scope.$on('$destroy', offClick);
function onClick() {
sync();
toggle();
update();
scope.$apply();
}
function offClick() {
iElement.off('click', onClick);
}
function sync() {
group = scope.$eval(iAttrs.group);
filter = scope.$eval(iAttrs.filter);
toggled = $filterCache.has(group, filter);
}
function toggle() {
toggled = !toggled;
if (toggled) {
$filterCache.put(group, filter);
} else {
$filterCache.remove(group, filter);
}
}
function update() {
if (toggled) {
iElement.addClass('toggled');
} else {
iElement.removeClass('toggled');
}
}
};
}
这里是原始示例的链接:JSFiddle