Adding a new operator in the search dialog - jqgrid

As filter operator you can choose from among:
'equal','not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains' and 'does not contain'.
I'd like to add an extra operator to this list. Can somebody point me in the right direction to achieve this?
The application is filtering using the dialog, and we are currently (very happily!) using free-jqgrid 4.15.0.
In case you wonder about the use case: our application has a date field and a very common filter is to filter records "due within X days from now". For best usability we don't like that users have to change the date filter every day.

Free jqGrid allows to define custom searching/filtering operation with respect of customSortOperations option. By default the corresponding custom compare operation will have two operands. Unary operations should be specified in customUnaryOperations option additionally. The feature is initially described in the wiki article. One can find some examples of usage the feature on the stackoverflow.
The custom compare/filter operators defined in customSortOperations need be included in the definition of the corresponding column in the array searchoptions.sopt. The demo uses the following code:
colModel: [
...
{ name: "name", align: "justify", width: 87, editrules: { required: true },
autoResizing: { minColWidth: 87 },
createColumnIndex: true,
searchoptions: {
generateDatalist: true,
sopt: [ "cn", "em", "nm", "in", "ni",
"teq", "tne",
"eq", "bw", "ew", "bn", "nc", "en" ],
clearSearch: true
} },
...
],
customUnaryOperations: ["em", "nm"],
customSortOperations: {
em: {
operand: "=''",
text: "is empty",
filter: function (options) {
var v = options.item[options.cmName];
if (v === undefined || v === null || v === "") {
return true;
}
}
},
nm: {
operand: "!=''",
text: "isn't empty",
filter: function (options) {
var v = options.item[options.cmName];
if (v !== undefined && v !== null && v !== "") {
return true;
}
}
},
teq: {
operand: "==",
text: "Turkish insensitive \"equal\"",
filter: function (options) {
var fieldData = String(options.item[options.cmName]).replace(/i/g,'İ').toUpperCase(),
searchValue = options.searchValue.replace(/i/g,'İ').toUpperCase();
return fieldData === searchValue;
}
},
tne: {
operand: "!=",
text: "Turkish insensitive \"not equal\"",
filter: function (options) {
var fieldData = String(options.item[options.cmName]).replace(/i/g,'İ').toUpperCase(),
searchValue = options.searchValue.replace(/i/g,'İ').toUpperCase();
return fieldData !== searchValue;
}
}
},
The code defines 4 custom operations: "em", "nm", "teq", "tne", where "em" ("is empty") and "nm" ("isn't empty") are unary operations. I get the code from my old answers: this one and another one.
The custom operations are available in searching toolbar and in the searching dialog:
I think it's the feature, which you need. I'd recommend you additionally to read another answer, which is close to your requirements. I think that simple modification of the code could solve your problem.

Related

Create a new column with sum of few other columns in jqgrid

I want to add a column which will contain summation of some columns.
Basically I want to convert following:
to the following:
But this has to be done dynamically i.e. I shall provide colModel id of th e columns I want the summation of.
P.S. Using 4.13.5 version of free-jqgrid.
The most easy way to implement your requirements would be the usage of jsonmap and sorttype defined as function, which returns the calculated value of the column. Additionally you would need to implement afterSetRow callback, which fixes the value after modification the row (after setRowData).
The corresponding implementation could be like in the demo. The demo defines the grid with total column, which displays the sum of amount and tax columns. The code of the demo looks as following:
var calculateTotal = function (item) {
return parseFloat(item.amount) + parseFloat(item.tax);
};
$("#list").jqGrid({
...
colModel: [
...
{ name: "amount", template: "number", ... },
{ name: "tax", template: "number", ... },
{ name: "total", width: 76, template: "number", editable: false,
jsonmap: function (item) {
return calculateTotal(item);
},
sorttype: function (cellValue, item) {
return calculateTotal(item);
}},
...
],
afterSetRow: function (options) {
var item = options.inputData;
if (item.total === undefined) {
// test is required to prevent recursion
$(this).jqGrid("setRowData", options.rowid, {
total: calculateTotal(item)
});
}
}
...
});

KendoGrid - After applying custom filter and then navigating to next or any other page, the filter values are not getting passed to controller

Used Kendo Version: 2015.2.624
I have implemented kendogrid server side paging with additional parameters. Below is how my controller looks like:
public ActionResult GetData([DataSourceRequest] DataSourceRequest request, DateTime startDate, DateTime endDate, int state = -1, string poolName = null, string submitter = null)
{
poolName = string.IsNullOrEmpty(poolName) ? null : poolName;
submitter = string.IsNullOrEmpty(submitter) ? null : submitter;
var summarylist = new List<Summary>();
var total = 0;
using (var db = new SummaryEntities())
{
var jobs = db.SummaryTable.Where(k => k.created >= startDate && k.created <= endDate)
.Where(k => state != -1 ? k.state == state : k.state > state)
.Where(k => poolName != null ? k.pool_name == poolName : k.pool_name != null)
.Where(k => submitter != null ? k.submitter == submitter : k.submitter != null);
jobs = jobs.OrderByDescending(job => job.id);
total = jobs.Count();
// Apply paging...
if (request.Page > 0)
{
jobs = jobs.Skip((request.Page - 1) * request.PageSize);
}
jobs = jobs.Take(request.PageSize);
foreach (var job in jobs)
{
summarylist.Add(new Summary(job));
}
}
var result = new DataSourceResult()
{
Data = summarylist,
Total = total
};
return Json(result, JsonRequestBehavior.AllowGet);
}
additional parameters are the current values which the user has set over the widget datepicker, input box etc.
Below is how my datasource looks like in grid:
<script type="text/javascript">
j$ = jQuery.noConflict();
j$(document).ready(function () {
j$("#grid").kendoGrid({
dataSource: {
transport: {
read: {
url: "/Home/GetData/",
dataType: "json",
data: {
startDate: j$("#startdate").val(),
endDate: j$("#enddate").val()
}
}
},
pageSize: 30,
serverPaging: true,
schema: {
data: 'Data',
total: 'Total'
}
},
height: j$(window).height() - 85,
groupable: true,
sortable: true,
filterable: false,
columnMenu: true,
pageable: true,
columns: [
{ field: "JobId", title: "Job Id", template: '#:JobId#', type: "number" },
{ field: "Name", title: "Job Name", hidden: true },
{ field: "PoolName", title: "Pool Name" },
{ title: "Date Time", columns: [{ field: "Start", title: "Start" },
{ field: "End", title: "End" }
],
headerAttributes: {
"class": "table-header-cell",
style: "text-align: center"
}
},
{ field: "State", title: "State" },
{
title: "Result", columns: [{ field: "ResultPassed", title: "P" },
{ field: "ResultFailed", title: "F" }
],
headerAttributes: {
"class": "table-header-cell",
style: "text-align: center"
}
},
{ field: "Submitter", title: "Submitter" }
]
});
});
</script>
It works pretty good until I observed this issue:
Change the filter values i.e submitter, date range etc and
controller gets all this information in additional parameters where
I am taking action accordingly and it works just fine.
Now suppose the result returned from step 1 has multiple pages and
when you click next page, or last page or any other page number, the
controller gets invoked which is expected but the additional
parameters being set in step 1 is not getting passed again instead
the default values are there which is ruining everything.
Correction:
Additional parameters are getting lost at client side only.
Now please tell me what am I missing here?
Expected Result: In step 2 additional parameters should not get lost and it should be same as step 1.
Any help is appreciated.
EDITED:
Complete controller and grid code.
Thanks,
Vineet
I got the solution from telerik support team:
Reply:
The described undesired behavior can be caused by the fact that the additional parameters:
data: {
startDate: j$("#startdate").val(),
endDate: j$("#enddate").val()
}
... are set to objects, instead of a functions. If they are set as functions, the values of the corresponding inputs will be evaluated every time read() is called, and the current values will be passed (like shown in the second example in the API reference):
http://docs.telerik.com/kendo-ui/api/javascript/data/datasource#configuration-transport.read.data

How to modifly kendoDatasource filter in requestStart

I have the following requestStart in my kendoDatasource:
requestStart: function (e) {
var oldFilters = e.sender._filter ? e.sender._filter.filters : [],
endDateTime;
$.each(oldFilters, function (index, currFilter) {
if (currFilter.field === 'StatusChangeDate' && currFilter.operator == 'eq') {
endDateTime = new Date(currFilter.value.getYear(), currFilter.value.getMonth(), currFilter.value.getDay(), 23, 59, 59);
oldFilters.push({ field: currFilter.field, operator: 'gt', value: currFilter.value });
oldFilters.push({ field: currFilter.field, operator: 'lt', value: endDateTime });
oldFilters.splice(index, 1);
}
});
if (e.sender._filter) {
e.sender._filter.filters = oldFilters;
}
},
I want to change DateTime filter when it's operator is 'eq', in order to disable filter precision.
But when I modify filter in requestStart like in the code above, it doesn't work. The request sends with old filter.
I don't know what I'm doing wrong. Is there another way to achieve behavior like this?
By the time requestStart is called, the query is already committed to being sent as is. The event is just letting you know but doesn't give you the opportunity to change anything.
Rather than try to sneak in the back way, just call the dataSource's filter() method to filter any way you want. DataSource will filter the data either locally or make a request to the server depending on the value of the serverFiltering option.
var filters = myDataSource.filter() || [],
endDateTime;
$.each(filters, function (index, currFilter) {
if (currFilter.field === 'StatusChangeDate' && currFilter.operator == 'eq') {
endDateTime = new Date(currFilter.value.getYear(), currFilter.value.getMonth(), currFilter.value.getDay(), 23, 59, 59);
filters.push({ field: currFilter.field, operator: 'gt', value: currFilter.value });
filters.push({ field: currFilter.field, operator: 'lt', value: endDateTime });
filters.splice(index, 1);
}
});
// Now apply the new filter to the dataSource.
// This will generate a request if serverFiltering == true.
myDataSource.filter(filters);
One other note, you should try to avoid accessing any property that starts with "_" as in "e.sender._filter". This is generally considered to be a "private" property which could change with the next version. You can get the current filter by calling filter() with no arguments as in the code above. This is another general rule in Kendo, no args mean get a value, args mean set a value.
EDIT
You can also hijack the CRUD requests to modify and/or add parameters using the dataSource's transport.parameterMap property. Note that this method will not modify the dataSource's filter properties. It only changes the request parameters going to the server.
$("#myGrid").kendoGrid({
// Column definitions, etc...
dataSource = new kendo.data.DataSource({
transport: {
// create, read, update, destroy definitions...
parameterMap: function(data, type) {
if ((type === "read") && data.filter && data.filter.filters) {
var filters = data.filter.filters;
for (var index = 0; index < filters.length, index++) {
var currFilter = filters[index];
if (currFilter.field === 'StatusChangeDate' && currFilter.operator == 'eq') {
endDateTime = new Date(currFilter.value.getYear(), currFilter.value.getMonth(), currFilter.value.getDay(), 23, 59, 59);
filters.push({ field: currFilter.field, operator: 'gt', value: currFilter.value });
filters.push({ field: currFilter.field, operator: 'lt', value: endDateTime });
filters.splice(index, 1);
break;
}
});
}
return data;
}
}
}),
});

KendoUI, tweaking the recurrence editor

With KendoUI 2013.3.1109
I am using KendoUI's scheduler
I am using a template for the reservation form, but via googling and perusing the forums, I read about re-using their recurrence form. I even figured out via experimenting that one could select which period options are available by, for instance, running:
$("#recurrenceEditor").kendoRecurrenceEditor(
{
frequencies: ["never", "daily", "weekly", "monthly"]
});
});
The code above will not load the 'yearly' option in the drop down.
There is no API documentation for kendoRecurrenceEditor on the website, but I was wondering if it is possible to tweak additional options, like removing the 'never' tag on when a recurrence should expire and so on.
So I initialize the Kendo recurrence editor:
$("#recurrenceEditor").kendoRecurrenceEditor({
change: function() {
onRecurrenceEditorChange();
}
});
Then I tweak what's visible inside #recurrenceEditor
var onRecurrenceEditorChange = function() {
var recurrenceKendoNumericTextBox = $('#recurrenceEditor .k-widget.k-numerictextbox.k-recur-count input[data-role="numerictextbox"]')
.data('kendoNumericTextBox');
if (recurrenceKendoNumericTextBox != null) {
var recurrenceEditorNeverEndOption = _container.find('#recurrenceEditor label:has(.k-recur-end-never)');
if (recurrenceEditorNeverEndOption != null)
recurrenceEditorNeverEndOption.hide();
recurrenceKendoNumericTextBox.max(10);
var recurrenceKendoDatePicker = _container.find('#recurrenceEditor .k-datepicker input[data-role="datepicker"]').data("kendoDatePicker");
if (recurrenceKendoDatePicker != null) {
var maxDate = window.moment().add('months', 2).toDate();
recurrenceKendoDatePicker.max(maxDate);
recurrenceKendoDatePicker.value(maxDate);
}
}
};
Then if you want to tweak the intervals, hack around it this way:
var recurrencePeriodKendoDropDownList = $('.k-widget.k-dropdown input[data-role="dropdownlist"]').data("kendoDropDownList");
var recurrencePeriodFilters = [
{
field: "value",
operator: "neq",
value: 'yearly'
}, {
field: "value",
operator: "neq",
value: 'monthly'
},
// if it's a newres, don't hide 'Never' option which matches to "",
{
field: "value",
operator: "neq",
value: someBoolConditionIhave ? "fake" : ""
}
];

jqGrid allows only numbers when editing cell

I want to prevent my user from typing letters inside a numeric field.
I saw that there is an option of: editrules:{number:true}, but this option will let the user click any key the user wants and only when row saved it will alert for illegal input. This is not good option for me. I want to prevent from the start the typing of keys that are not numbers (for example in a regular input I can use jQuery's .numeric()).
How can this be done?
{name:'actualNo',index:'actualNo',editable:true, edittype:"text", width:150,editoptions:{
size: 15, maxlengh: 10,
dataInit: function(element) {
$(element).keyup(function(){
var val1 = element.value;
var num = new Number(val1);
if(isNaN(num))
{alert("Please enter a valid number");}
})
}
}},
I don't use jQuery.numeric plugin myself, but I suppose you should use dataInit property of editoptions for the corresponding grid column:
editoptions: { dataInit: function (elem) {
$(elem).numeric(/*some optional parameters*/);
}
}
or in case of some trouble in the form
editoptions: { dataInit: function (elem) {
setTimeout(function(){
$(elem).numeric();
}, 100);
}
}
I hope it will work.
{name:'rate',index:'rate', align:"left", width:'150',editable:true,
edittype:"text", editoptions:{
size: 25, maxlengh: 30,
dataInit: function(element) {
$(element).keypress(function(e){
if (e.which != 8 && e.which != 0 && (e.which < 48 || e.which > 57)) {
return false;
}
});
}
}
},

Resources