问题
I have implemented a ui-grid with server side filtering, sorting and pagination.
I use gridApi.core.on.filterChanged to detect filter change alongside $timeout
to wait for user to finish typing. It's not bad idea to use $timeout
, but I want to filter grid only on enter
key, but filterChanged
event watches the value of field and I think it doesn't have access to keypress nor keydown events to detect enter
key.
How can I call ajax filter on enter
key?
回答1:
Solution found!
As I told before, I was searching for a "CLEAN" solution to avoid adding headerCellTemplate
to all columns and changing lots of my code.
This solution is somehow based on overriding ui-grid's cellHeaderTemplate
to use my custom directive as input filter, and it works great. I can also add different types of filters to my grid.
angular
.module('ui.grid')
.run(['$templateCache', function ($templateCache) {
// Override uiGridHeaderCell template to replace "input" field with "grid-filter" directive
$templateCache.put('ui-grid/uiGridHeaderCell',
"<div ng-class=\"{ 'sortable': sortable }\"><div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\"><span>{{ col.displayName CUSTOM_FILTERS }}</span><span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\"> </span></div><div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader && col.colDef.enableColumnMenu !== false\" ng-click=\"toggleMenu($event)\" ng-class=\"{'ui-grid-column-menu-button-last-col': isLastCol}\"><i class=\"ui-grid-icon-angle-down\"> </i></div><div ng-if=\"filterable\" class=\"ui-grid-filter-container\" ng-repeat=\"colFilter in col.filters\"><grid-filter type=\"{{colFilter.type}}\"></grid-filter><div class=\"ui-grid-filter-button\" ng-click=\"colFilter.term = null\"><i class=\"ui-grid-icon-cancel\" ng-show=\"!!colFilter.term\"> </i><!-- use !! because angular interprets 'f' as false --></div></div></div>"
);
// Add custom templates to use in "grid-filter" directive
$templateCache.put('ui-grid-filters/text',
"<input type=\"text\" class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-attr-placeholder=\"{{colFilter.placeholder || ''}}\">"
);
$templateCache.put('ui-grid-filters/dropdown',
"<select class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" ng-options=\"option.text for option in colFilter.dropdownOptions \"><option value=''></option> </select>"
);
$templateCache.put('ui-grid-filters/date',
"<input type='text' class=\"ui-grid-filter-input\" ng-model=\"colFilter.term\" mask=\"1399/99/99\" mask-options=\"{placeholder:' '}\" placeholder='{{colFilter.placeholder}}' />"
);
}])
.directive('gridFilter', ['$templateCache', '$compile', function ($templateCache, $compile) {
return {
restrict: 'AE',
replace: true,
link: function (scope, elem, attrs) {
var type = attrs['type'] || 'text';
var grid = scope.$parent.$parent.grid;
var filter = function () {
// Filtering comes here. We have full access to grid and it's filter terms here.
};
var template = $compile($templateCache.get('ui-grid-filters/' + type))(scope);
elem.replaceWith(template);
elem = template;
elem.keypress(function (e) {
if (e.which == 13) {
filter();
}
});
if (type == 'dropdown') {
elem.change(function (e) {
filter();
})
}
// Handle clear button click action
scope.$watch('$parent.colFilter.term', function (newVal, oldVal) {
if (newVal === null && oldVal !== null) {
filter();
}
});
}
}
}]
);
And here is a sample gridOptions
object.
$scope.gridOptions = {
enableFiltering: true,
enableRowSelection: true,
enableGridMenu: true,
paginationPageSizes: [25, 50, 75],
paginationPageSize: 25,
useExternalSorting: true, // Sorting is handled using gridApi.core.on.sortChanged() event
useExternalFiltering: true, // Filtering is handled in custom directive
useExternalPagination: true, // Pagination is handled using gridApi.pagination.on.paginationChanged() event
columnDefs: [
{
field: 'username',
displayName: "Username"
},
{
field: 'status',
displayName: 'Status',
cellTemplate: '<div class="text-center">' +
'<span ng-show="row.entity.status==1">Enabled</span>' +
'<span ng-show="row.entity.status==2">Disabled</span>' +
'</div>',
filter: {
type: 'dropdown',
dropdownOptions: [
{
id: 1,
text: 'Enabled'
},
{
id: 2,
text: 'Disabled'
}
]
}
},
{
field: 'birthDate',
displayName: 'Birth Date',
filters: [
{
type: 'date',
placeholder: 'From'
},
{
type: 'date',
placeholder: 'To'
}
]
},
]
}
回答2:
The filterChanged event only tells you that it's changed, it doesn't filter individual key presses. The best option would be to implement a custom filter template using the new custom filter options: http://ui-grid.info/docs/#/tutorial/306_custom_filters, and then implement your logic directly on the filter directive that you provide. Note that you'll need the latest unstable for this - it will release in RC21 or 3.0, whichever comes first.
回答3:
Filter event of ui grid calls with watch of the modal,but watch method calls on keypress so we can change the keypress event to blur event of text box by adding the directive
directive('ngModelOnblur', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elm, attr, ngModelCtrl) {
elm.unbind('input').unbind('keydown').unbind('blur');
elm.bind('change', function () {
scope.$apply(function () {
ngModelCtrl.$setViewValue(elm.val());
});
});
}
};
});
add the directive in textbox
of uigrid
and ui grid filter.api called only on change event of textbox
or enter key.
来源:https://stackoverflow.com/questions/29726521/angular-ui-grid-filter-when-user-presses-enter-key