Let's assume I have a database with 2 tables. First table is location codes. Second table is event records. Event records contain a location code ID.
Edit: tables weren't working apparently, so I took a screenshot of the preview
And I am using Kendo Grid to display the data. On the server when I get the data I package it so that my location column is stored as an array.
$rowdata['location'] = array('location_id' => $data['location_id'], 'location_code' => $data['location_code']);
I use a template in my grid to display only the code.
The trouble that I am having is when using client-side filtering on this or other similarly formatted columns. I am aware that this would be much easier to accomplish using server-side filtering, however there are reasons why this is not being used.
What I am attempting to do is to modify the operator value during the filter event of the grid.
var customOperators = {};
$('#grid').kendoGrid({
...
filterMenuOpen: function (e) {
// since the custom operator does not exist, no operator is selected when the menu is re-opened. select the one last used for this field.
if (customOperators.hasOwnProperty(e.field)) {
$(e.container.find('select[data-bind="value: filters[0].operator"]')).data('kendoDropDownList').value(customOperators[e.field]);
}
},
filter: filterOpChange
});
function filterOpChange(e) {
if (e.filter === null) {
if (customOperators.hasOwnProperty(e.field)) {
delete customOperators[e.field];
}
return;
}
let oldOp = e.filter.filters[0]['operator'];
if (typeof window[e.field + '_' + oldOp] === "function") {
customOperators[e.field] = oldOp; // store the old operator in an object to re-select it from the list when the filter menu opens
e.filter.filters[0]['operator'] = window[e.field + '_' + oldOp]; // assign function named [field_name]_[operator] to the operator
}
}
// eq
function location_eq(itemVal, filterVal) {
return (itemVal && itemVal.location_id !== null && filterVal !== null && parseInt(itemVal.location_id) === parseInt(filterVal));
}
// neq
function location_neq(itemVal, filterVal) {
return (itemVal && itemVal.location_id !== null && filterVal !== null && parseInt(itemVal.location_id) !== parseInt(filterVal));
}
And this works. It filters as I expect it to. However, there is a problem if I attempt to change the filter for this field. If I change the filter menu from equals to does not equal I get a JavaScript error. In Chrome the error message is:
In Firefox the error message is (cut off the last file which is the file that has the grid on it):
The reason that I am using custom operators instead of a standard dropdown list is because I want to be able to filter based only on the text values so that a user can filter for "locA" and locA_1, locA_2, and locA_3 will all be displayed. The sample code I provided does not do this exactly, instead it looks at the ID, but that was easier to include here. I would appreciate any help with resolving the issue of applying a filter to a column that uses objects for values whether that means fixing my current error or going about it in a different way so long as it stays client-side.
Related
In my Rails I have two models, both with a method giving JSON back. One model is rent.rb the other is buy.rb. I also have a map.js, which will show a map with different pins, depending on the model, basically. So one map shows pins with apartments to rent, another - with apartments to buy. So, now I need a tooltip with a different information, depending on buy / rent. So I defined this part (as it's not coming from database), for rent.rb:
information {
...
type: "rent"
}
and for buy.rb with :
information {
...
type: "buy"
}
So now, in my map.js I wish to find out type and depending on what I get show the right information
(type == "rent") ? (show information for rent) : (type == "buy") ? (show information for buy)
But somehow JS won't access this value and won't customize information shown. Unfortunatelly I can't show the code, as it's for work. But maybe I am just using the wrong syntax here ...
You cannot join conditional operators like way you showed. Also you cannot have a function between ? and :
It will be better to do something like this
var rentInformation="some value";
var buyInformation="some other value";
var displayInformation = (type == "rent") ? rentInformation : buyInformation;
somePopupFunction(displayInformation);
I'm currently looking for a way to add a filter function to a list in SharePoint, which filters the lists content via checkbox selection.
This little mockup might help to understand what I'm talking about:
The idea is to have a normal SharePoint custom list on the right and a checkboxlist on the left side, which will be generated dynamically from the content of the list -> One column is a "filter group" and all the field contents are the filter values.
When selecting one or multiple values on the left side, the items in the list should instantly be filtered accordingly (ajax, without reloading the page).
For example in the mockup, selecting "New York" and "Blue" would only show the item "Steve's Car".
You now, like a product filter in almost every online shop and so on.
How can that be achieved? Would be awesome if this could be included in my solution package (which includes other stuff in C#/jQuery already).
I'm new to frontend customization in SharePoint, but I'm sure there's a way :-)
Edit: I'm using SP2016 by the way.
Pandora!
As i understand it, your first question is how you can dinamically get values for left side filter. I see there two ways: first way, you can build caml query and get items from list; second way, you can use ctx.ListData, which sharepoint initialize by itself and in ctx.ListData.Row (array of items) process items and get unique field values. Note, that ctx.ListData.Row contains only items loaded in list view on the page.
For list filtration you can concat filter link for hash of the page. Example: "?List={ListID}&View={ViewID}&FilterField1=Color-FilterValue1=Blue". Try to filter columns on list and you will see url modification. ListID and ViewId you can retrieve by ctx.listName and ctx.view.
And then pass it in function MyRefreshPageToEx. List will be filtered.
More list filtration info
function FilterList(){
var tableId = $(".ms-listviewtable").attr("id");
var filterUrl = "?List={ListID}&View={ViewID}&FilterField1=Color-FilterValue1=Blue";
MyRefreshPageToEx(tableId, filterUrl, false);
}
function MyRefreshPageToEx(lvTableID, url, bForceSubmit) {
var tblv = document.getElementById(lvTableID);
var clvp = CLVPFromCtx(tblv);
if (clvp != null && clvp.ctx.IsClientRendering) {
clvp.RefreshPaging(url);
clvp.ctx.queryString = url;
if ((typeof clvp.ctx.operationType == "undefined" || clvp.ctx.operationType == SPListOperationType.Default) && Boolean(clvp.ctx.ListData)) {
var fromPage = clvp.ctx.ListData.FirstRow - 1;
var toPage = Number(GetUrlKeyValue("PageFirstRow", false, url));
if (!isNaN(fromPage) && !isNaN(toPage) && fromPage != toPage)
fromPage < toPage ? (clvp.ctx.operationType = SPListOperationType.PagingRight) : (clvp.ctx.operationType = SPListOperationType.PagingLeft);
}
}
else {
SubmitFormPost(url, bForceSubmit);
}
}
I have a pretty standard jqGrid using free-jqGrid 4.13 with loadonce: true;
What I want to do is something I came across a couple of times:
I want to save the state of the grid (without the data);
that means the settings (number of current page for example), filters the user applied and also the text in the filter-toolbar.
and then load and apply this data to the grid later.
jqGrid is such a powerful tool, but stuff like this seems such a pain to accomplish.
after hours and hours of work i came up with a complicated solution; it is working, but it's not a nice solution imho:
1) saving jqGrid filter-data (locally):
// in this example i am using the "window unload" event,
// because i want the filters to be saved once you leave the page:
$(window).on("unload", function(){
// i have to access the colModel in order to get the names of my columns
// which i need to get the values of the filter-toolbar textboxes later:
var col_arr = $("#list").jqGrid("getGridParam", "colModel");
// my own array to save the toolbar data:
var toolbar_search_array = [];
for(var i = 0, max = col_arr.length; i < max; i++)
{
// only saving the data when colModel's "search" is set to true
// and value of the filterToolbar textbox got a length
// the ID of the filterToolbar text-input is "gs_" + colModel.name
if(col_arr[i].search && $("#gs_" + col_arr[i].name).val().length)
{
toolbar_search_array.push({ name: col_arr[i].name, value: $("#gs_" + col_arr[i].name).val() });
}
}
// putting everything into one object
var pref = {
// 1. toolbar filter data - used to fill out the text-inputs accordingly
toolbar : toolbar_search_array,
// 2. postData - contains data for the actual filtering
post : $("#list").jqGrid("getGridParam", "postData"),
// 3. settings - this data is also included in postData - but doesn't get applied
// when using 'setGridParam'
sortname: $('#list').jqGrid('getGridParam', 'sortname'),
sortorder: $('#list').jqGrid('getGridParam', 'sortorder'),
page: $('#list').jqGrid('getGridParam', 'page'),
rowNum: $('#list').jqGrid('getGridParam', 'rowNum')
};
//saving in localStorage
localStorage.setItem("list", JSON.stringify( pref ));
});
2) loading and applying jqGrid filter-data:
for use in a document-ready closure, for example
var localsave = JSON.parse(localStorage.getItem("list"));
// these settings are also saved in postData,
// but they don't get applied to the grid when setting the postData:
$('#list').jqGrid('setGridParam', {
sortname: localsave.sortname,
sortorder: localsave.sortorder,
page: localsave.page,
rowNum: localsave.rowNum
});
// this applies the filtering itself and reloads the grid.
// it's important that you don't forget the "search : true" part:
$("#list").jqGrid("setGridParam", {
search : true,
postData : localsave.post
}).trigger("reloadGrid");
// this is loading the text into the filterToolbar
// from the array of objects i created:
console.log(localsave.toolbar);
for(i = 0, max = localsave.toolbar.length; i < max; i++)
{
$("#gs_" + localsave.toolbar[i].name).val( localsave.toolbar[i].value );
}
it seems strange to me that postData contains all the data necessary but it's impossible to apply this data; at least as far as i know.
my question(s):
is it really this inconvenient to apply all the filter- and paging-data or am i missing something?
why can't this be as simple as:
// saving:
var my_save = $("#list").jqGrid("getGridParam", "postData");
// loading:
$("#list").jqGrid("setGridParam", {
search : true,
postData : my_save
}).trigger("reloadGrid");
?
thank you for any help and/or suggestions!
The answer with the demo provides an example of the implementation. The method refreshSerchingToolbar is relatively long. On the other side the code is still not full. It's not restore the state of operands, if the option searchOperators: true is used. I wanted to rewrite many parts of the filterToolbar method to make easier the saving/restoring of the the state of the filter toolbar or refreshing based on the changed postData. It's just the problem of the time and nothing more. What you describe is close to the feature forceClientSorting: true, which was difficult to implement in original code of jqGrid 4.7, but it was easy to implement after I rewrote large part of processing of the server response. The same problem is with the code of filterToolbar. The changes of filterToolbar is still in my TODO list and I'll made the corresponding changes soon.
I am using something similair to this:
$("input").each(function(number,element)
{
var inputField=$(element);
if(inputField.data("FieldLocalizationStrings") == null)
inputField.data("FieldLocalizationStrings", []);
}
And to add data:
var data=inputField.data("FieldLocalizationStrings");
data.push({Language:inputField.attr("language"),Value:inputField.val()});
But when i try to retreive, it seems to ignore on which DOM element it has been saved and just loads it like it was all saved on the same element. Anyone an idea why this would happen? i have used the same technique before and it proved to work, but now i can't figure out why this is hapening.
I confirmed it does not save it to multiple input fields, but when loading it acts like it is.
Update
Added a fiddle here
$("input").each(function(number,element)
{
var inputField=$(element);
if(inputField.data("FieldLocalizationStrings") == null)
inputField.data("FieldLocalizationStrings", [
{
Language:inputField.attr("language"),
Value:inputField.val()
}
]);
//If later you want to append to the data
inputField.data("FieldLocalizationStrings").push({/* Your data */})
}
http://api.jquery.com/jQuery.each/ - as for documentation you'll get value as second parameter. If you want set data for an element you should use this.
I found many discussions that were close to what I need, and this question is the
closest - How can I set postData._search to true in the request in jqGrid?.
As I'm struggling with almost the same problem, and just can't get it working - I want to setup "search" and "filters" during the initial loading of the jqGrid - say, on the page reload, and I have my filters stored in the session - and I tried everything I found in Oleg's examples - it just doesn't work!
That's what I'm trying to do -
loadBeforeSend: function (xhr) {
var grid = jQuery('#' + block_id);
var postData = grid.jqGrid('getGridParam','postData');
jQuery.extend(postData,{filters:MyFilters});
grid.jqGrid('setGridParam', {search: true, postData: postData});
console.log(grid.jqGrid('getGridParam','postData'));
}
The console printout shows that the filters are in place, but the _search is still false, and the actual Post gets sent even with no filters:
_search false
block_id report_block_1table
nd 1297451574526
page 1
rows 25
sidx id
sord desc
However, if I put exactly the same code - with the addition of
grid.trigger("reloadGrid");
line - into some button's onClickButton function, and later click the button - everything works; but I need to make it work on "page reload"!
Any ideas? It's driving me crazy...
It seems to me that you are not the first person who ask the same question. Recently I asked on the close question (read many comments to the answer). Another old answer including the demo could probably answer on some your opened questions.
Your code using beforeRequest don't work just because the function beforeRequest will be caled immediately before the ajax call and the changing of the search parameter is too late. Moreover overwiting of filters everytime is probably not the best idea. In the case the user will not able to set any other grid filter.
So I can repeat, that the imlementation of the solution which you need is very simple. You should just set filters property of the postData parameter of jqGrid to the filter which you need and set another jqGrid parameter search:true additionally. It's all! Later the user will be able to open advance searching dialog and overwrite the filters. The user can also click on "Reset" button of the advance searching dialog and set filters to empty string and search:false.
For better understanding I have to clear how search parameter or some other jqGrid will be used in the URL. There are parameter prmNames of jqGrid which defines the names of parameters send as a part of URL or as a part of data POSTed to the server. The default value of prmNames contain search:"_search" and the code of internal populate function used by jqGrid has the following simplified code fragment:
var prm = {}, pN=ts.p.prmNames;
if(pN.search !== null) {prm[pN.search] = ts.p.search;}
if(pN.nd !== null) {prm[pN.nd] = new Date().getTime();}
if(pN.rows !== null) {prm[pN.rows]= ts.p.rowNum;}
if(pN.page !== null) {prm[pN.page]= ts.p.page;}
if(pN.sort !== null) {prm[pN.sort]= ts.p.sortname;}
if(pN.order !== null) {prm[pN.order]= ts.p.sortorder;}
...
$.extend(ts.p.postData,prm);
where
prmNames: {page:"page",rows:"rows", sort: "sidx",order: "sord", search:"_search",
nd:"nd", id:"id",oper:"oper",editoper:"edit",addoper:"add",
deloper:"del", subgridid:"id", npage: null, totalrows:"totalrows"}
So to set _search parameter of URL one should set search parameter of jqGrid.
Look at the following demo. You can easy to verify using Fiddler of Firebug that the jqGrid from the page send HTTP GET with the following url:
http://www.ok-soft-gmbh.com/jqGrid/MultisearchFilterAtStart1.json?filters=%7B%22groupOp%22%3A%22AND%22%2C%22rules%22%3A%5B%7B%22field%22%3A%22invdate%22%2C%22op%22%3A%22gt%22%2C%22data%22%3A%222007-09-06%22%7D%2C%7B%22field%22%3A%22invdate%22%2C%22op%22%3A%22lt%22%2C%22data%22%3A%222007-10-04%22%7D%2C%7B%22field%22%3A%22name%22%2C%22op%22%3A%22bw%22%2C%22data%22%3A%22test%22%7D%5D%7D&_search=true&nd=1297508504770&rows=10&page=1&sidx=id&sord=asc
So it do exactly what you need. The code of the demo contain the following code fragment:
$("#list").jqGrid({
url: 'MultisearchFilterAtStart1.json',
datatype: "json",
postData: {
filters:'{"groupOp":"AND","rules":['+
'{"field":"invdate","op":"gt","data":"2007-09-06"}'+
',{"field":"invdate","op":"lt","data":"2007-10-04"}'+
',{"field":"name","op":"bw","data":"test"}]}'
},
search:true,
// ...
});
#Oleg Oleg's answer works like a charm but just for the first time.
For me when I reload the grid, filters and search flag are not set up.
With the following code each time I reload the grid it also sends the filters and search flag.
I use server side sort and pagination.
I'm using:
jQuery("#myGrid").navGrid("#myPager", {search: true, refresh: true, edit: false,
add:false, del:false}, {}, {}, {}, {});
On the grid definition:
beforeRequest: function() {
// filter to be added on each request
var filterObj1 = {"field":"myField","op":"eq","data":"myValue"};
var grid = jQuery("#myGrid");
var postdata = grid.jqGrid('getGridParam', 'postData');
if(postdata != undefined && postdata.filters != undefined ) {
postdata.filters = jQuery.jgrid.parse(postdata.filters);
//Remove if current field exists
postdata.filters.rules = jQuery.grep(postdata.filters.rules, function(value) {
if(value.field != 'myField')
return value;
});
// Add new filters
postdata.filters.rules.push(filterObj1);
} else {
jQuery.extend(postdata, {
filters: {
"groupOp":"AND",
"rules":[filterObj1]
}
});
// more filters in the way: postdata.filters.rules.push(filterObj1);
}
postdata.filters = JSON.stringify(postdata.filters);
postdata._search = true;
return [true,''];
}