I have developed some js to enable the filtering of connected fields in the "Add Filter" modal.
I started by creating a new object that holds all the filter "Rules". It looks like this:

The records atm look like this:

In my example below, "Staff" is field_1304 and based on my rules above, I only want to show staff records where field_1308 (which is status) is Active. I get this info from scene_3118 and view_6577.

Here is the js:
//////////////////////////////////////////////////////////////////////////////
// This function gets all the filter rules and stores them in a global array.
// The scene and view are specified in the url.
// The fields are specified to match the fields in the created filter rule object.
// Within this function is the only place that code needs to change when moving the code to another Knack App.
var getFilterRules = function () {
var tryAttempts = 0;
// load the filter records
var recordUrl = "https://api.knack.com/v1/pages/scene_3119/views/view_6578/records/";
var recordUrl = recordUrl + "?rows_per_page=500";
$.ajax( {
url: recordUrl,
type: "GET",
dataType: 'JSON',
headers: {
'Authorization': Knack.getUserToken(),
'X-Knack-Application-ID': Knack.application_id,
'X-Knack-REST-API-Key': 'knack'
},
tryCount : tryAttempts,
retryLimit : 5,
success: function (filterData) {
//Loop through filterData, build g_fC
for (var i = 0; i < filterData.total_records; i++) {
g_fC[i] = { //filter Record
id: filterData.records[i].id, //Record Id
s_field: filterData.records[i].field_3318, //Selected Filter Field
t_field: filterData.records[i].field_3319, //Field To Test
t_operator: filterData.records[i].field_3320, //Operator to use
t_value: filterData.records[i].field_3321, //Value to test against
t_scene: filterData.records[i].field_3322, //Ajax Scene
t_view: filterData.records[i].field_3323, //Ajax View
descriptor: filterData.records[i].field_3324 //Descriptor for Filter List Dropdown
}
}
return g_fC;
},
error : function (request, status, error) {
tryAttempts = this.tryCount++;
if (this.tryCount <= this.retryLimit) {
var endTime = new Date();
var startTime = new Date();
do {
endTime = new Date();
} while (endTime - startTime < 200);
$.ajax(this);
}
}
});
}
// This is where the global variables are declared and the filter rules loaded into an array (once only)
var g_filtersObjectLoaded;
if (!g_filtersObjectLoaded) { // Only load this once
g_filtersObjectLoaded = true;
var g_fC = []; // Filters Collection
var g_fL = []; // Filters List array - used on the Filter Form
getFilterRules();
}
// To catch the filter form, need to bind on to something that is always there.
// The filter form is dynamically created so need to start at a higher level than where it appears.
var knackDistEl = document.getElementById(“knack-dist_1”);
$(knackDistEl).on(“click”, “#kn-filters-form”, function (event) {
// isTrigger indicates the “Add Filters” button has been clicked. When this happens, need to reset array
// and reload any previously selected filters
if (event.isTrigger) {
g_fL = ; // Reset Filters List array when filter form displayed
}
var filterFormEl = document.getElementById(“kn-filters-form”);
var filterFieldEls = filterFormEl.getElementsByClassName(“field select”); // This is the left hand side of the filter
// Go through each row of filter lines
for (var j = 0; j < filterFieldEls.length; j++) {
var filterFieldEl = filterFieldEls[j];
var filterFieldOptions = filterFieldEl.getElementsByTagName("option");
var optCount = filterFieldOptions.length;
// Find the field selected in each filter row
for (var i = 0; i < optCount; i++) {
if (filterFieldOptions[i].selected == true) {
var selectedField = filterFieldOptions[i];
break;
}
}
// Compare the selected field to the value in our array.
// If it is not the same then load it in the array and compare against the filter rules
if (selectedField.value != g_fL[j]) {
g_fL[j] = selectedField.value;
var arrRules = [];
var k = 0;
var matchRule = [];
// Go through all the rules in g_fC and see if the selectedField.value matches any rules
// If it does (could be multiple rules) add the rules to the array called arrRules
var filterCount = g_fC.length;
for (var i = 0; i < filterCount; i++) {
if (g_fC[i].s_field == selectedField.value) {
matchRule = {
'field': g_fC[i].t_field, 'operator': g_fC[i].t_operator, 'value': g_fC[i].t_value
}
arrRules[k] = matchRule;
k++;
var t_scene = g_fC[i].t_scene;
var t_view = g_fC[i].t_view;
var descriptor = g_fC[i].descriptor;
}
}
// If we have any rules matching, make the Ajax call
if (k > 0) {
var filterValueEls = filterFormEl.getElementsByClassName("kn-filter-value");
var filterNumber = j;
var pFilterValueEl = filterValueEls[filterNumber];
// Protect the Filter Value field until we have reloaded
pFilterValueEl.classList.add("protected-fields");
getFilterList(arrRules, t_scene, t_view, descriptor, filterNumber, function (filterList, fNumber) {
var incSelected = true;
var filterValueEl = filterValueEls[fNumber];
var filterListEls = filterValueEl.querySelectorAll("select");
var filterListEl = filterListEls[0];
// Delay 0.5 seconds as sometimes our build is faster than the initial load
var delayInMilliseconds = 500; //0.5 second
setTimeout(function () {
loadFilterList(filterListEl, filterList, incSelected, function () {
filterValueEl.classList.remove("protected-fields");
});
}, delayInMilliseconds);
});
}
}
}
});
var loadFilterList = function (filterListEl, filterList, incSelected, callback) {
var selectVal = [];
// Need to start at the end and work backwards when removing options.
var L = filterListEl.options.length - 1;
for (var i = L; i > 0; i--) { // To keep 'Select' then leave the first option in place. ie >0, not >=0
var selectedOption = filterListEl.options[i].getAttribute("selected");
if (selectedOption != null) {
selectVal[i] = filterListEl.options[i].value;
}
filterListEl.options.remove(i);
}
// Rebuild the options based on the retrieved data
for (var i = 0; i < filterList.length; i++) {
// Create an Option object
var opt = document.createElement("option");
// Assign text and value to Option object
opt.value = (filterList[i][0]);
opt.text = (filterList[i][1]);
if (incSelected) {
for (j = 0; j < selectVal.length; j++) {
if (opt.value === selectVal[j]) opt.selected = "selected";
}
}
// Add Option object to Drop Down List
filterListEl.add(opt);
}
// Update the list
$("#" + filterListEl.id).trigger("liszt:updated").change();
$("#" + filterListEl.id).chosen().trigger("change");
callback();
}
var getFilterList = function (arrRules, t_scene, t_view, descriptor, filterNumber, callback) {
var tryAttempts = 0;
var filterList = [];
// Prepare filters
var filters = {
'match': 'and',
'rules': arrRules
}
var recordUrl = "https://api.knack.com/v1/pages/" + t_scene + "/views/" + t_view + "/records";
var filterUrl = '?rows_per_page=500&filters=' + encodeURIComponent(JSON.stringify(filters));
var totalRecordUrl = recordUrl + filterUrl;
$.ajax( {
url: totalRecordUrl,
type: "GET",
dataType: 'JSON',
headers: {
'Authorization': Knack.getUserToken(),
'X-Knack-Application-ID': Knack.application_id,
'X-Knack-REST-API-Key': 'knack'
},
tryCount : tryAttempts,
retryLimit : 5,
success: function (data) {
for (var i = 0; i < data.total_records; i++) {
filterList[i] = [data.records[i].id, data.records[i][descriptor]];
}
callback(filterList, filterNumber);
},
error : function (request, status, error) {
tryAttempts = this.tryCount++;
console.log(tryAttempts);
if (this.tryCount <= this.retryLimit) {
var endTime = new Date();
var startTime = new Date();
do {
endTime = new Date();
} while (endTime - startTime < 200);
$.ajax(this);
}
}
});
}
// Make sure all the filter selections on all views are not clickable.
$(document).on(‘knack-view-render.any’, function (event, view, data) {
var viewEl = document.getElementById(view.key);
if (viewEl != null) {
var editFilterEls = viewEl.querySelectorAll(".kn-edit-filter");
for (var i = 0; i < editFilterEls.length; i++) {
editFilterEls[i].classList.add(“protected-fields”);
}
}
});
and a little bit of CSS:
/* Protects Fields while loading */
.protected-fields {
pointer-events: none;
opacity: 0.4; /* Opacity is for test use only */
}
If you have any questions, suggestions or improvements, please let me know.
Tony