Javascript: filter menus AND advanced filtering - your tables can now have both!

Hi to all,

My gift of the day!

This solution addresses a limitation regarding filters in tables.

I found that often I'd need to have both the filter menus and advanced filtering options for a given table.

But it's is not possible by default.

Now using this simple technique, you can now have it both ways with just a checkbox.

  • Create your table with all the filter menus that you need.
  • Re-create that same table to the same page, just below, but with the option "Enable users to filter records" under Filter instead. Note: you can also copy it instead of re-creating. But this is a two-step process because for some reason you can't copy a view to the same page.
    1. Create a dummy blank page, without login. This page is only there as a temporary placeholder.
    2. Copy the table to the blank page
    3. Move it back to the original page. Don't forget to enable Filtering.
    4. You may delete the blank page. I keep it there for future copy operations.
  • Copy/paste your "table pair" view_XYZ and replace those in the code below.

This code uses cookies, which is the first time ever I use them. Really cool and easy!

One nice side effect of this technique is that your filtering settings are persistent when you toggle from one mode to the other, since we're only hiding/showing two views, not re-creating them.

Enjoy,
Norm

Cortex R&D Inc.
ctrnd.com

///////////////////////////////////////////////////////////
//Add Toggle Filter Mode checkbox to view pairs.
const MY_REPORT1_MF = 'view_123'; //Scene 1
const MY_REPORT1_AF = 'view_124';
const MY_REPORT2_MF = 'view_234'; //Scene 2
const MY_REPORT2_AF = 'view_235';

var g_menuFilterView = null;
var g_userFilterView = null;
var g_tableObj1 = null;
var g_tableObj2 = null;

$(document).on(
'knack-view-render.' + MY_REPORT1_MF + ' knack-view-render.' + MY_REPORT1_AF +
' knack-view-render.' + MY_REPORT2_MF + ' knack-view-render.' + MY_REPORT2_AF,
function (event, view, data) {
if (view.type === 'table' && view.filter_type === 'menu') {
g_menuFilterView = view.key;
g_tableObj1 = view.source.object;
}
else if (view.type === 'table' && view.filter_type === 'fields') {
g_userFilterView = view.key;
g_tableObj2 = view.source.object;
}

if (g_menuFilterView !== null && g_userFilterView !== null & (g_tableObj1 === g_tableObj2 /*For good luck*/))
addFilterToggleCheckbox(g_menuFilterView, g_userFilterView);
}
)

//////////////////////////////////////////////////////
function addFilterToggleCheckbox(menuFilterView = null, advancedFilterView = null) {
if (menuFilterView === null || advancedFilterView === null) {
console.log('Called addFilterToggleCheckbox with incomplete parameters.');
return;
}

$(document).ready(function () {
var menu = $(".js-filter-menu:first");
menu.css('display', 'inline-flex');
console.log(menu);

var filter = $(".kn-filters-nav");
console.log(filter);
filter.css('display', 'inline-flex');

var label = document.getElementById('filter-label-id');
var checkbox = document.getElementById('toggle-full-filter-id');
var checkboxStyle = "width: 26px; height: 26px; padding: 0; margin-left: 40px; margin-right: 5px; vertical-align: middle; position: relative";

if (checkbox === null) {
checkbox = document.createElement('input');
checkbox.type = "checkbox";
checkbox.id = "toggle-full-filter-id";

label = document.createElement('label');
label.htmlFor = "toggle-full-filter-id";
label.setAttribute('id', 'filter-label-id');
label.appendChild(document.createTextNode('Advanced Filter'));
}

var useAdvancedFilter = getCookie('AdvancedFilterMode-' + menuFilterView + '-' + advancedFilterView);
if (useAdvancedFilter === 'YES') {
checkbox.checked = true;
label.setAttribute('style', 'margin-right: 25px');
filter.prepend(checkbox, label);
$('#' + menuFilterView).css('display', 'none');
$('#' + advancedFilterView).css('display', 'block');
}
else {
checkbox.checked = false;
var vertAdj = 'margin-top: 5px'; //To fine-tune vertical alignment.
checkboxStyle += ';' + vertAdj;
label.setAttribute('style', vertAdj);
menu.append(checkbox, label);
$('#' + menuFilterView).css('display', 'block');
$('#' + advancedFilterView).css('display', 'none');
}

checkbox.setAttribute("style", checkboxStyle);

checkbox.addEventListener('change', function () {
if (this.checked) {
document.cookie = 'AdvancedFilterMode-' + menuFilterView + '-' + advancedFilterView + '=YES';
refreshView(advancedFilterView);
} else {
document.cookie = 'AdvancedFilterMode-' + menuFilterView + '-' + advancedFilterView + '=NO';
refreshView(menuFilterView);
}
});
})
}

///////////////////////////////////////////////////////////
function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}


Important update to everyone reading this!

Do not use this method. I was unexperienced back then. Way too complicated and risky to get out-of-sync between both views.

Instead, use KTL with the new Public Filters feature.

To see more about the KTL, go here: cortexrd/Knack-Toolkit-Library: Knack Toolkit Library (github.com)

Normand D.