我尝试使用服务器端排序,服务器端分页和服务器端过滤来实现角度网格。使用ui-grid(不稳定),我添加了ui.grid.paging并使所有内容都运行起来。非常好,对开发人员赞不绝口。
然而.... $ scope.gridApi.core.on.filterChanged正在按下每个按键,所以当我搜索" Patrick"在givenname列中,触发了七个事件,七个get-requests命中了我的服务器。更糟糕的是,由于它是一个很大的过滤器,这个操作非常昂贵,结果我甚至相互超越,就像最特殊的过滤器获得最快的结果一样,在处理不太具体的结果之前触发成功。
我想放慢速度,就像在进入停止后开火一样#34;。我对javascript和REST非常陌生,这是我的第一个真实世界项目。我真的很感激如何处理这个问题的任何想法。这感觉就像一个常见的场景,因此可能会有一些我缺少的标准解决方案或最佳实践。
此致, 帕特里克。
答案 0 :(得分: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);
}
});
答案 1 :(得分:9)
我正在处理同样的问题,我提出了另一个解决方案,恕我直言更多" Angular-friendly"。我使用了Angular 1.3中引入的ngModelOptions directive。 我用自定义的模板替换了uiGrid的默认过滤器模板(" ui-grid / ui-grid-filter"),并在输入上配置了ngModelOptions指令,默认去抖值为300 ms,模糊0毫秒。
这是一个基于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\"> </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\"> </i></div></div>" +
"</div>"
);
此操作的最后一步是在您启用过滤的每个columnDef中设置此模板:
columnDefs: [{
name: 'theName',
displayName: 'Whatever',
filterHeaderTemplate: 'ui-grid/ui-grid-filter-custom'
}]
不幸的是,我找不到任何方法来全局定义这个模板,所以我不得不在任何地方重复filterHeaderTemplate ......这是唯一的缺点,但另一方面,你也可以添加如果需要,可以为自定义模板添加更多过滤器。
希望它有所帮助!
答案 2 :(得分:1)
我建议你看一下reactive-extensions for Javascript。 Reactive专为这些场景而构建。有一个名为.Throttle(毫秒)的方法,你可以将它附加到一个observable,它将在x毫秒过去之后调用一个处理程序(命中你的API),以便用户不输入任何内容。
Rx-Js and angular play well together
以下是我的一个类似项目的例子:
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做一个值的类型查找,所以每当一个字母发生变化时点击后端显然不是这样的方法:)
答案 3 :(得分:0)
JavaScript setTimeout 函数也可用于提供延迟,如下所示。
$scope.gridApi.core.on.filterChanged( $scope, function() {
if (angular.isDefined($scope.filterTimeout)) {
clearTimeout($scope.filterTimeout);
}
$scope.filterTimeout = setTimeout(function(){
getPage();
},1000);
});