6

我正在尝试使用服务器端排序、服务器端分页和服务器端过滤来实现有角度的网格。使用 ui-grid(不稳定),我添加了 ui.grid.paging 并让一切正常运行。非常好,向开发者致敬。

但是.... $scope.gridApi.core.on.filterChanged 每按下一个键就会触发,所以当我在 givenname 列中搜索“Patrick”时,会触发七个事件,并且有七个 get-requests 到达我的服务器。更糟糕的是,由于我要过滤的集合很大,所以这个操作非常昂贵,结果甚至会相互超越,比如最具体的过滤器获得最快的结果,在处理不太具体的结果之前触发成功。

我想放慢速度,比如“进入停止后开火”。我对 javascript 和 REST 非常陌生,这是我的第一个真实世界项目。我真的很感激如何处理这个问题的任何想法。这感觉像是一个常见的场景,所以我可能缺少一些标准解决方案或最佳实践。

你的,帕特里克。

4

4 回答 4

16

如果你想“全角”,我建议在事件处理程序$timeout内部使用:on.filterChanged

if (angular.isDefined($scope.filterTimeout)) {
    $timeout.cancel($scope.filterTimeout);
}
$scope.filterTimeout = $timeout(function () {
    getPage();
}, 500);

其中 500 是您希望在每个 on.filterChanged 事件之间等待的时间(以毫秒为单位),然后再转到服务器,而 getPage() 是实际转到服务器并检索数据的函数。

不要忘记取消$timeout控制器的“销毁”事件:

$scope.$on("$destroy", function (event) {
    if (angular.isDefined($scope.filterTimeout)) {
        $timeout.cancel($scope.filterTimeout);
    }
});
于 2014-12-04T22:32:05.747 回答
9

我正在处理同样的问题,我想出了另一个解决方案,恕我直言,它更“Angular-friendly”。我使用了 Angular 1.3 中引入的ngModelOptions 指令。我将 uiGrid 的默认过滤器模板(“ui-grid/ui-grid-filter”)替换为自定义过滤器模板,并将输入上的 ngModelOptions 指令配置为默认去抖动值 300 ms 和 0 ms 用于模糊。

这是一个基于 ui-grid 3.0.5 原始模板的示例模板,我还通过 Bootstrap 类更改了默认 CSS 类:

$templateCache.put('ui-grid/ui-grid-filter-custom',
  "<div class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\" ng-class=\"{'ui-grid-filter-cancel-button-hidden' : colFilter.disableCancelFilterButton === true }\">" +
  "<div ng-if=\"colFilter.type !== 'select'\"><input type=\"text\" class=\"input-sm form-control\" ng-model=\"colFilter.term\" ng-model-options=\"{ debounce : { 'default' : 300, 'blur' : 0 }}\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\" aria-label=\"{{colFilter.ariaLabel || aria.defaultFilterLabel}}\"><div role=\"button\" class=\"ui-grid-filter-button\" ng-click=\"removeFilter(colFilter, $index)\" ng-if=\"!colFilter.disableCancelFilterButton\" ng-disabled=\"colFilter.term === undefined || colFilter.term === null || colFilter.term === ''\" ng-show=\"colFilter.term !== undefined && colFilter.term !== null && colFilter.term !== ''\"><i class=\"ui-grid-icon-cancel\" ui-grid-one-bind-aria-label=\"aria.removeFilter\">&nbsp;</i></div></div>" +
  "<div ng-if=\"colFilter.type === 'select'\"><select class=\"form-control input-sm\" ng-model=\"colFilter.term\" ng-attr-placeholder=\"{{colFilter.placeholder || aria.defaultFilterLabel}}\" aria-label=\"{{colFilter.ariaLabel || ''}}\" ng-options=\"option.value as option.label for option in colFilter.selectOptions\"><option value=\"\"></option></select><div role=\"button\" class=\"ui-grid-filter-button-select\" ng-click=\"removeFilter(colFilter, $index)\" ng-if=\"!colFilter.disableCancelFilterButton\" ng-disabled=\"colFilter.term === undefined || colFilter.term === null || colFilter.term === ''\" ng-show=\"colFilter.term !== undefined && colFilter.term != null\"><i class=\"ui-grid-icon-cancel\" ui-grid-one-bind-aria-label=\"aria.removeFilter\">&nbsp;</i></div></div>" +
  "</div>"
);

最后一步是在启用过滤的每个 columnDef 中设置此模板:

columnDefs: [{
  name: 'theName',
  displayName: 'Whatever',
  filterHeaderTemplate: 'ui-grid/ui-grid-filter-custom'
}]

不幸的是,我找不到任何方法来全局定义这个模板,所以我不得不到处重复 filterHeaderTemplate ......这是唯一的缺点,但另一方面,如果需要,您还可以向自定义模板添加更多过滤器至。

希望能帮助到你!

于 2015-09-12T21:52:15.503 回答
1

我建议您看一下Javascript 的响应式扩展。Reactive 正是为这类场景而构建的。有一个名为 .Throttle(milliseconds) 的方法,您可以将其附加到一个 observable 上,该方法将在 x 毫秒后调用处理程序(以访问您的 API),因为用户没有输入任何内容。

Rx-Js 和 angular 配合得很好

这是我做类似事情的一个项目中的一个例子:

observeOnScope($scope, 'tag', true)
            .throttle(1000)
            .subscribe(function (data) {
                if (data.newValue) {
                    $http({
                        url: api.endpoint + 'tag/find',
                        method: 'GET',
                        params: {text: data.newValue}
                    }).then(function (result) {
                        $scope.candidateTags = result.data;
                    })
                }
            });

此代码$scope.tag将其转换为可观察的。这.throttle(1000)意味着在$scope.tag不更改订阅函数的 1 秒后将调用其中 (data) 是新值。之后,您可以点击您的 API。

我用它来预先从我的 API 中查找值,所以每次更改字母时都点击后端显然不是要走的路:)

于 2014-12-04T21:16:17.413 回答
0

JavaScript setTimeout函数也可用于延迟,如下所示。

$scope.gridApi.core.on.filterChanged( $scope, function() {

    if (angular.isDefined($scope.filterTimeout)) {
        clearTimeout($scope.filterTimeout);
    }
    $scope.filterTimeout = setTimeout(function(){
        getPage();
    },1000);

});
于 2016-02-15T07:32:57.627 回答