How to link external filter components with table filter?

I have a table see below.

I want to connect the checkboxes with the filter option of the table.

  1. I have played a little bit with table.setFilter and setFilterStack. I did not exactly know what table.updateLinkedFilter() should do?
  2. My solution looks like (see below). Do you know if there is a better way?

pcbPage_sqlQuery_setTableFilterByComponents to update the filter setting of the table (called when a checkbox is changed):

const productionOnlyStatus = pcbPage_checkbox_productionOnly.value;
const showDeletedStatus = pcbPage_checkbox_showDeleted.value;
//const appMode = var_appMode;

var stack = pcbPage_table_pcb.filterStack;
console.log(stack);

var productionOnlyFilter = {columnId: "productionStatusName", operator: "=", value: "In Production", id: "pcbPage_checkbox_productionOnly"};

var notDeletedOnlyFilter = {columnId: "deleted", operator: "=", value: false, id: "pcbPage_checkbox_showDeleted"};
console.log(stack);

// handle filter
var filter = [];
if (productionOnlyStatus) {
  filter.push(productionOnlyFilter)
}
if (!showDeletedStatus) {
  filter.push(notDeletedOnlyFilter)
}

// handle stack
stack = {filters: filter, operator: "and"}

// set stack
pcbPage_table_pcb.setFilterStack(stack);
pcbPage_table_pcb.updateLinkedFilter(stack);

pcbPage_sqlQuery_setComponentsByTableFilter to update to checbox settings if somebody changed the filter settings of the table by hand (called when filter of table is changed):

// get stack
var stack = pcbPage_table_pcb.filterStack;
console.log(stack);
// get app mode
const appMode = var_appMode.value;

// set helper variables
var productionOnlyFound = false;
var showDeletedFound = false;

// if stack is not null
if (stack != null)
{
  // search for ids and at found flag
  for (const element of stack.filters) {
    if ('id' in element)
    {
      if (element.id == 'pcbPage_checkbox_productionOnly')
      {
        console.log("pcbPage_checkbox_productionOnly");
        productionOnlyFound = true;
      }
      else if (element.id == 'pcbPage_checkbox_showDeleted')
      {
        console.log("pcbPage_checkbox_showDeleted");
        showDeletedFound = true;
      }
    }
  }
}

// set checkboxes
if (productionOnlyFound) {
  pcbPage_checkbox_productionOnly.setValue(true);
}
else
{
  pcbPage_checkbox_productionOnly.setValue(false);
}
if (!showDeletedFound) {
  // handle error in case of viewer mode
  if (appMode == 'viewer') {
    // show error
    utils.showNotification({
      title: "Filter Change Error",
      description: "In viewer mode you can't display deleted items!",
      notificationType: "error",
      duration: 4.5,
    });
    // retun set filter stack query
    pcbPage_sqlQuery_setTableFilterByComponents.trigger()
  }
  else {
    pcbPage_checkbox_showDeleted.setValue(true);
  }
}
else
{
  pcbPage_checkbox_showDeleted.setValue(false);
}

Thanks a lot!

Hi @bauergeorg,

Update Table Filters When Checkbox Changes
Modify pcbPage_sqlQuery_setTableFilterByComponents to apply the table filters dynamically:

const productionOnlyStatus = pcbPage_checkbox_productionOnly.value;
const showDeletedStatus = pcbPage_checkbox_showDeleted.value;

// Define filters
let filters = [];

if (productionOnlyStatus) {
  filters.push({ columnId: "productionStatusName", operator: "=", value: "In Production", id: "pcbPage_checkbox_productionOnly" });
}
if (!showDeletedStatus) {
  filters.push({ columnId: "deleted", operator: "=", value: false, id: "pcbPage_checkbox_showDeleted" });
}

// Apply filter stack
pcbPage_table_pcb.setFilterStack({ filters, operator: "and" });

// Ensure table updates correctly
pcbPage_table_pcb.updateLinkedFilter();

Sync Checkbox Values When Table Filter Changes

Modify pcbPage_sqlQuery_setComponentsByTableFilter to update checkbox values dynamically:

// Get current filter stack
const stack = pcbPage_table_pcb.filterStack || { filters: [] };

// Determine applied filters
const productionOnlyFound = stack.filters.some(f => f.id === "pcbPage_checkbox_productionOnly");
const showDeletedFound = stack.filters.some(f => f.id === "pcbPage_checkbox_showDeleted");

// Update checkboxes
pcbPage_checkbox_productionOnly.setValue(productionOnlyFound);
pcbPage_checkbox_showDeleted.setValue(!showDeletedFound); // If filter is missing, set it to true

// Handle Viewer Mode Restriction
if (!showDeletedFound && var_appMode.value === 'viewer') {
  utils.showNotification({
    title: "Filter Change Error",
    description: "In viewer mode, you can't display deleted items!",
    notificationType: "error",
    duration: 4.5,
  });

  // Reapply correct filters
  pcbPage_sqlQuery_setTableFilterByComponents.trigger();
}
1 Like

Thank you @Shawn_Optipath to optimize my code. I use javascript since a couple of weeks. I am very glad about your optimizations!

To the pcbPage_sqlQuery_setComponentsByTableFilter: I changed it like the following code:

// Get current filter stack
const stack = pcbPage_table_pcb.filterStack || { filters: [] };

// Determine applied filters
const productionOnlyFound = stack.filters.some(f => f.id === "pcbPage_checkbox_productionOnly");
const showDeletedFound = stack.filters.some(f => f.id === "pcbPage_checkbox_showDeleted");

// Update checkbox 'in production only'
pcbPage_checkbox_productionOnly.setValue(productionOnlyFound);

// Handle Viewer Mode Restriction
if (!showDeletedFound && var_appMode.value === 'viewer') {
  utils.showNotification({
    title: "Filter Change Error",
    description: "In viewer mode, you can't display deleted items!",
    notificationType: "error",
    duration: 4.5,
  });
  // Update checkbox 'show deleted' set to false
  pcbPage_checkbox_showDeleted.setValue(false);
  // Reapply correct filters
  pcbPage_sqlQuery_setTableFilterByComponents.trigger();
}
else {
  // Update checkbox 'show deleted'
  pcbPage_checkbox_showDeleted.setValue(!showDeletedFound);
}

Your code stucks in a endless loop. when deleting the filter for deleted rows of the table. Thank you very much. Could Retool optimize the description of the function table.updateLinkedFilter()? My code runs wonderful without this function... I am very confused...

Hi @bauergeorg. Let's try to fix this.

The endless loop occurs because, when you remove the "Show Deleted" filter, the script sets the checkbox back to false. Then, it triggers the pcbPage_sqlQuery_setTableFilterByComponents function to reapply the filter. This re-adds the filter, which triggers the table filter change again. The cycle keeps repeating indefinitely.

Let's modify your function to only update the checkboxes if necessary, and prevent triggering pcbPage_sqlQuery_setTableFilterByComponents again if it's already correcting the filter.

// Get current filter stack
const stack = pcbPage_table_pcb.filterStack || { filters: [] };

// Determine applied filters
const productionOnlyFound = stack.filters.some(f => f.id === "pcbPage_checkbox_productionOnly");
const showDeletedFound = stack.filters.some(f => f.id === "pcbPage_checkbox_showDeleted");

// Update checkbox 'in production only'
pcbPage_checkbox_productionOnly.setValue(productionOnlyFound);

// Handle Viewer Mode Restriction
if (!showDeletedFound && var_appMode.value === 'viewer') {
  utils.showNotification({
    title: "Filter Change Error",
    description: "In viewer mode, you can't display deleted items!",
    notificationType: "error",
    duration: 4.5,
  });

  // Prevent an infinite loop by checking if the checkbox is already false
  if (pcbPage_checkbox_showDeleted.value !== false) {
    pcbPage_checkbox_showDeleted.setValue(false);
    
    // Prevent unnecessary recursive trigger
    setTimeout(() => {
      pcbPage_sqlQuery_setTableFilterByComponents.trigger();
    }, 100); // Small delay to prevent immediate retrigger loop
  }
} else {
  // Update checkbox 'show deleted' only if needed
  if (pcbPage_checkbox_showDeleted.value !== !showDeletedFound) {
    pcbPage_checkbox_showDeleted.setValue(!showDeletedFound);
  }
}
2 Likes

Thank you @Shawn_Optipath I prefer my solution. My function mentioned here also prevents infinite loop.

Could somebody help?

  1. I did not exactly know what table.updateLinkedFilter() should do? Can somebody explain it? I think I don't need this function.
  2. My solution looks like (see above). Do you know if there is a better way?

To the second question: It seems not. @Shawn_Optipath has a lot of retool experience. If he optimize my approach, this way is the best way to synchronize external filter components with the table.
To the first question: @Tess Is it possible to get an example for the usage of table.updateLinkedFilter()?

Greetings and thanks a lot!
Georg

Hi @bauergeorg,

Thanks for reaching out about this

updateLinkedFilter is helpful if you add a filter component to your app and link it to a table. Then, you can programmatically add filters to the filter component: