AngularJS切换按钮过滤器

时间:2016-01-28 19:41:52

标签: javascript jquery html angularjs

所以这是从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

2 个答案:

答案 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}}&nbsp;</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>