Requirement:
Implement ‘exact match’ filter against the list view web part on text values and drop down values using AJAX for great user performance. An alternative to filtering in a fly out menu of the list view web part’s column values.
Filter by ‘Title’
Technique:
I am essentially emulating the column based filters that are out-of-the-box functionality of the SharePoint 2013 List view web parts. I do this by tracking down how the filtering is executed in the SharePoint inplview.js code. Then wrap the filtering JavaScript logic through custom text boxes.
You can see the URL query string parameters reflect the filtering
/SitePages/Tickets.aspx#InplviewHashdba27ef6-7bff-4c0f-8ec1-b3e3e18fb0b8=FilterField1=LinkTitle-FilterValue1=Printer broken
For large lists (i.e. > 5,000 items), keep in mind to index the columns you want to filter by. You can find the setting in the List Settings page and find a link ‘Indexed Columns’
<table style="" border="0"> <tr> <td>Title:</td> <td><input type="text" id="title" onblur="TitleFilter(); return false;" /></td> <td> <button onclick="TitleFilter(); return false;">Filter by Title</button> </td> </tr> <tr> <td> Task Status: </td> <td> <input type="text" id="taskStatus" onblur="TaskStatusFilter(); return false;" /> </td> <td> <button onclick="TaskStatusFilter(); return false;">Filter by Task Status</button> </td> </tr> <tr> <td></td> <td></td> <td> <button onclick="TitleAndTaskStatusFilter(); return false;">Filter by Title AND Task Status</button> </td> </tr> </table>
<script language='javascript'> function MyRefreshPageToEx(lvTableID, url, bForceSubmit) { // Hardcode reference to list view <table> Id attribute var tblv = document.getElementById("{BE9A90D1-BF5D-401B-8A9B-C44CCCD14241}-{DBA27EF6-7BFF-4C0F-8EC1-B3E3E18FB0B8}"); 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); } } function TitleFilter() { var title = $('#title').val() var url; if (title) { url = "?List={BE9A90D1-BF5D-401B-8A9B-C44CCCD14241}&View={DBA27EF6-7BFF-4C0F-8EC1-B3E3E18FB0B8}&FilterField1=LinkTitle&FilterValue1=" + title } inplview.MyRefreshPage = MyRefreshPageToEx; inplview.MyRefreshPage(null, url, null); } function TaskStatusFilter() { var taskStatus = $('#taskStatus').val() var url; if (taskStatus) { url = "?List={BE9A90D1-BF5D-401B-8A9B-C44CCCD14241}&View={1F1B1E55-992B-4A03-98B2-9E5D34916611}&FilterField1=TaskStatus&FilterValue1=" + taskStatus } inplview.MyRefreshPage = MyRefreshPageToEx; inplview.MyRefreshPage(null, url, null); } function TitleAndTaskStatusFilter() { var title = $('#title').val() var taskStatus = $('#taskStatus').val() // HARD Code: query string to reference List GUID and View ID var url = "?List={BE9A90D1-BF5D-401B-8A9B-C44CCCD14241}&View={DBA27EF6-7BFF-4C0F-8EC1-B3E3E18FB0B8}&ViewCount=1&IsXslView=TRUE&IsCSR=TRUE&"; if (title && taskStatus) { url = url + "FilterField1=LinkTitle&FilterValue1=" + title + "&FilterField2=TaskStatus&FilterValue2=" + taskStatus } else if (title && !taskStatus) { url = url + "FilterField1=LinkTitle&FilterValue1=" + title } else if (!title && taskStatus) { url = url + "FilterField1=TaskStatus&FilterValue1=" + taskStatus } inplview.MyRefreshPage = MyRefreshPageToEx; inplview.MyRefreshPage(null, url, null); } </script>
There is some hard coding in the custom JavaScript code making references to the list view web part such as the table Id, list GUID and view GUID.
Find the table element Id as follows.
Limitations
- Inplview.js filtering only supports exact match of values and not partial match
- OR operand is not supported in the inpview.js from what I can see.
- This custom approach is a bit of “hack”. Since it is client side, there is no impact to the SharePoint farm on the server side. Nevertheless, follow any development guidelines in your team. At the least, regression testing is recommended on SharePoint product patching and upgrades for any breaking changes.
The solution fit
I think the better solution fit is where the user already knows exactly what to filter on, but doesn’t want to scroll a largest list of values through the OOTB column filters every single time. For example, filtering by exact name or a small number.
Reblogged this on SutoCom Solutions.
Great stuff! Question for you: I am using JSLink to build a custom URL so users can filter by managed metadata by simply clicking a term. My code works on page load, but after I do my first filter the javascript no longer loads. This happens because JS executes on page load, not when inplview.js is called.
How can I attach my javascript function to inplview so it’ll execute after every list refresh?
Hi,
The OR command is also working, you just need to change the following:
– FilterFields1 instead of FilterField1 and FilterValues1 instead of FilterValue1
– The Values should be separated by ‘;#’
– The values should be URL encoded
Example (will display the items with ID 1 or 2):
FilterFields1=ID&FilterValues1=2%3B%231
Cheers,
Attila
Thanks for that clarification of the ‘OR’ operand support!
Some Jquery to get rid of the hardcoded GUIDs and IDs.
// Assuming you have placed a WebPart for a Custom List on your page, then
// there is a table rendered for the list. This is the name you originally
// named your list. Not any rename in an edited web part in a span.
//
// CALL => $(“table[summary=’OSIRDetails’]”).getGUIDsForTable();
//
// RESULTS returned in hash
// =============================================================
// webPartDivID => MSOZoneCell_WebPartWPQ3
// tableID => {E2AA3C69-B35C-4EA1-A995-FD7E055287D8}-{A16C050C-A384-405F-B717-E532008039A5}
// ctxNum => 59
// ctxNumObj => [object Object]
// listGUID => {E2AA3C69-B35C-4EA1-A995-FD7E055287D8}
// viewGUID => {A16C050C-A384-405F-B717-E532008039A5}
// listGUIDenc => %7BE2AA3C69-B35C-4EA1-A995-FD7E055287D8%7D
// viewGUIDenc => %7BA16C050C-A384-405F-B717-E532008039A5%7D
$.fn.getGUIDsForTable = function() {
var $thisTable = $(this); // See how to call above
if($thisTable !== null) {
var grid = false;
var $webPartDiv = $thisTable.closest(“div[id^=’MSOZoneCell_WebPartWPQ’]”);
var webPartDivID = $webPartDiv.attr(“id”);
if($webPartDiv.find(“div[id^=’spgridcontainer’]”).length > 0){
$webPartDiv = $webPartDiv.find(“.ms-listviewgrid”);
webPartDivID = $webPartDiv.attr(“id”);
grid = true;
}
$webPartDiv.find(“.ms-viewheadertr th”).each(function (i) {
var $thisHeader = $(this);
if(grid){
$webPartDiv.data(“ctxNum”, $thisHeader.closest(“tbody”).find(“tr:nth-child(2)”).attr(“iid”).split(“,”)[0]);
}
else {
$webPartDiv.data(“ctxNum”, $thisHeader.find(‘div:first’).attr(‘CtxNum’));
}
});
var ctxNum = $webPartDiv.data(“ctxNum”);
var results = {};
if(ctxNum !== undefined) {
results[‘webPartDivID’] = webPartDivID;
results[‘tableID’] = $thisTable.attr(“id”);
results[‘ctxNum’] = ctxNum;
results[‘ctxNumObj’] = eval(“ctx” + ctxNum);
results[‘listGUID’] = results[‘ctxNumObj’].listName;
results[‘viewGUID’] = results[‘ctxNumObj’].view;
results[‘listGUIDenc’] = encodeURIComponent(results[‘listGUID’]);
results[‘viewGUIDenc’] = encodeURIComponent(results[‘viewGUID’]);
}
for(var key in results) {
console.log(key + ” => ” + results[key]);
}
}
return results;
}; // getGUIDsForTable
Thanks. This is a nice dictionary to abstract away from GUIDs from the list view web part elements.
Thank you for that solution, Roy 🙂 Works fine
I can’t get it to work… I just get the message “Unable to get property ‘clvp’ of undefined or null reference”
I figured out that it is the function “CLVPFromCtx(ctxParam)” in INPLVIEW.js, but I have no idea how to fix this
I had the same issue, but I solved it when I used the GUID with capital letters.
I got to this solution when I copied and pasted the GUID from the source code of my site. And since the GUID in the script of Roy is also in capital letters it could work out for you too if your ID was in small letters. It just gave me the error when I used small letters in the ID.
Thanks for thsi solution, Roy! It works fine with 1 web part, how can I use it with 2 web parts??
Not sure about 2 web parts. But probably apply the same approach with one web part to both point to the same custom JS functions to execute. It’s been so long since I’ve done any further work on this auto-refresh. Hope other reading this post and working on it an provide suggestions.
Can i use drop downs(jquery Drop downs) instead of text boxes
You can try with the JSlink approach as this is framework to extend lists views with client side renderings.
Thanks its working fine as expected