所以这是从jQuery应用程序到Angular应用程序的javascript转换。当前的jQuery应用程序可以工作,但需要使用Angular框架制作一个真正的应用程序。
整个应用程序背后的逻辑是选择类别并过滤OUT并根据过滤器按钮获得特定结果。因此,假设您只希望看到仅包含过滤器1和过滤器2在一起的结果,而不是(过滤器1,过滤器2和过滤器1 +过滤器2)。请参阅jquery版本:demo
$(document).ready(function(){
$('.filter-selector').click(function(){
/* Filter 1 Categories */
if($(this).attr("value")==".filter1_group1"){
$(".filter1_group1-show").toggle();
$(this).toggleClass('active');
}
if($(this).attr("value")==".filter1_group2"){
$(".filter1_group2-show").toggle();
$(this).toggleClass('active');
}
});
});
现在我需要将javascript魔术转换为角度,将按钮保持在切换状态并在第二个视图上显示结果。它基本上是Angular SPA,有2个视图:1表示过滤器,1表示结果。以前的应用程序使用jQuery切换类函数,但在这种情况下没有Angular的内置函数。 Angular的切换按钮的所有示例都只有1个切换按钮,用于隐藏/显示div。其他示例按钮仅分别显示或隐藏div,而不是切换按钮。如何将过滤结果转换为服务返回,然后将其作为结果注入View 2并显示它们?
在这里需要Angular众神的一些指示...
更新1: thanx到Shaun Scovil,找到了创建此过滤器组的Angular方式。但是,过滤器组在单个页面上运行良好,但在2个视图SPA应用程序中不能正常运行:plunkr在过滤器和案例之间切换几次后,过滤器将会中断。
再次更新2: thanx到Shaun Scovil,过滤器/案例切换按钮现在可以从页面视图转到页面视图,返回到任意数量的视图:plunkr
答案 0 :(得分:7)
根据您的示例应用和说明,以下是我将如何用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元素添加功能。在您的情况下,我会创建一个带有“点击”的指令。可以作为属性添加到按钮或任何其他元素的事件处理程序。事件处理程序可以使用我们的$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>
根据评论,我通过对ngRoute
进行以下更改来更新JSFiddle示例以使用toggleFilterDirective
:
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
答案 1 :(得分:-1)
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>
<script>
var app = angular.module('App', []);
app.service('serviceFilters', function() {
var filters = [
{
name: 'Filter 1',
groups: [
{
name: 'Group 1',
selected: false
},
{
name: 'Group 2',
selected: false
}
]
},
{
name: 'Filter 2',
groups: [
{
name: 'Group 1',
selected: false
},
{
name: 'Group 2',
selected: false
}
]
}
],
getFilters = function () {
return filters;
},
isCase12Selected = function () {
return filters[0].groups[0].selected && filters[0].groups[1].selected && !filters[1].groups[0].selected && !filters[1].groups[1].selected;
},
isCase1Selected = function () {
return filters[0].groups[0].selected && !filters[0].groups[1].selected && !filters[1].groups[0].selected && !filters[1].groups[1].selected;
},
isCase2Selected = function () {
return !filters[0].groups[0].selected && filters[0].groups[1].selected && !filters[1].groups[0].selected && !filters[1].groups[1].selected;
},
isCase13Selected = function () {
return filters[0].groups[0].selected && !filters[0].groups[1].selected && filters[1].groups[0].selected && filters[1].groups[1].selected;
},
isCase4Selected = function () {
return !filters[0].groups[0].selected && !filters[0].groups[1].selected && !filters[1].groups[0].selected && filters[1].groups[1].selected;
};
return {
getFilters: getFilters,
isCase12Selected: isCase12Selected,
isCase1Selected: isCase1Selected,
isCase2Selected: isCase2Selected,
isCase13Selected: isCase13Selected,
isCase4Selected: isCase4Selected
};
});
app.filter('selectedGroups', function() {
return function(groups) {
return groups.filter(function (group) {
return group.selected;
});
};
});
app.directive(
'viewApplication',
[
'serviceFilters',
function (serviceFilters) {
'use strict';
return {
restrict: 'E',
template:
'<div>' +
'<view-filters></view-filters>' +
'<view-selected></view-selected>' +
'<view-cases></view-selected>' +
'</div>',
controller: ['$scope', function ($scope) {
$scope.serviceFilters = serviceFilters;
}]
};
}
]
);
app.directive(
'viewFilters',
[
'serviceFilters',
function (serviceFilters) {
'use strict';
return {
restrict: 'E',
scope: {},
template:
'<div>' +
'<h1>Filters</h1>' +
'<div ng-repeat="filter in serviceFilters.getFilters()">' +
'<h2>{{::filter.name}}</h2>' +
'<div ng-repeat="group in filter.groups">' +
'<span>{{::group.name}} </span>' +
'<button ng-click="group.selected=!group.selected">{{group.selected ? \'Unselect\' : \'Select\'}}</button>' +
'</div>' +
'</div>' +
'</div>',
controller: ['$scope', function ($scope) {
$scope.serviceFilters = serviceFilters;
}]
};
}
]
);
app.directive(
'viewSelected',
[
'serviceFilters',
function (serviceFilters) {
'use strict';
return {
restrict: 'E',
scope: {},
template:
'<div>' +
'<h1>Selected</h1>' +
'<div ng-repeat="filter in serviceFilters.getFilters()">' +
'<div ng-repeat="group in filter.groups | selectedGroups">' +
'{{filter.name}} | {{group.name}}' +
'</div>' +
'</div>' +
'</div>',
controller: ['$scope', function ($scope) {
$scope.serviceFilters = serviceFilters;
}]
};
}
]
);
app.directive(
'viewCases',
[
'serviceFilters',
function (serviceFilters) {
'use strict';
return {
restrict: 'E',
scope: {
filters: '='
},
template:
'<div>' +
'<h1>Cases</h1>' +
'<span ng-if="serviceFilters.isCase12Selected()">Case 1,2</span>' +
'<span ng-if="serviceFilters.isCase1Selected()">Case 1</span>' +
'<span ng-if="serviceFilters.isCase2Selected()">Case 2</span>' +
'<span ng-if="serviceFilters.isCase13Selected()">Case 1,3</span>' +
'<span ng-if="serviceFilters.isCase14Selected()">Case 4</span>' +
'</div>',
controller: ['$scope', function ($scope) {
$scope.serviceFilters = serviceFilters;
}]
};
}
]
);
</script>
</head>
<body ng-app="App">
<view-application></view-application>
</body>
</html>