# Architecting a Centralized Column Visibility Manager for Dynamic Perspective Tables

**URL:** <https://forum.inductiveautomation.com/t/architecting-a-centralized-column-visibility-manager-for-dynamic-perspective-tables/114352>\
**Category:** Ignition\
**Tags:** ignition81, perspective\
**Created:** [March 5, 2026, 10:38pm UTC](https://forum.inductiveautomation.com/t/architecting-a-centralized-column-visibility-manager-for-dynamic-perspective-tables/114352 "2026-03-05T22:38:26Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Farhan\_Basheer](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/farhan_basheer/32/66759_2.png) [@Farhan\_Basheer](https://forum.inductiveautomation.com/u/Farhan_Basheer)\
**Post date:** [March 5, 2026, 10:38pm UTC](https://forum.inductiveautomation.com/t/architecting-a-centralized-column-visibility-manager-for-dynamic-perspective-tables/114352/1 "2026-03-05T22:38:26Z")

</div>

I am managing 20+ Perspective Table components across multiple views. Many of these tables are dynamic—their columns change based on query parameters or user selection. I need a scalable, centralized system that allows users to toggle column visibility via a popup, remembers their preferences for the session, and handles dynamic column generation without hardcoding.

**Description:** I currently use a custom Python module to dynamically generate table columns. I want to extend this system to include a "Column Manager" popup that works for any table in the project.

**My Proposed Architecture:**

1. **Centralized Storage:** A Session Custom Property dictionary `session.custom.ColumnPreferences` that stores visibility states keyed by a unique `tableId` (e.g., `{"TableA": {"Station": True, "Timestamp": False}}`).
2. **Universal Popup:** A single View containing a Table component. This table will display the column names and a boolean checkbox. It will be passed a `tableId` and the current `columnNames` list as parameters.
3. **The Logic:**

- A helper function `applyColumnVisibility(generatedCols, tableId, prefs)` that intercepts the column configuration before it is applied to the component.
- It should default any "newly discovered" dynamic columns to `Visible: True` if they aren't yet in the user's preference dictionary.

**Goal:** I want to ensure this is the most performant way to handle this in Perspective. Specifically:

- Should I be using `onEditCellCommit` on the popup table to write directly back to the Session prop?
- Is there a better way to "discover" available columns for the popup than passing them from the parent table's current data?

I'm looking for feedback on this "Hub-and-Spoke" model or any tips on how others have handled persistent column states across large-scale projects.

---

<div class="post-metadata">

**Author:** ![ryan.white](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryan.white/32/73193_2.png) [@ryan.white](https://forum.inductiveautomation.com/u/ryan.white)\
**Post date:** [March 5, 2026, 11:24pm UTC](https://forum.inductiveautomation.com/t/architecting-a-centralized-column-visibility-manager-for-dynamic-perspective-tables/114352/2 "2026-03-05T23:24:39Z")

</div>

The centralized storage method more or less lines up with what I have recommended to others in the past for holding similar user specific information, like personalization and such. You could expand it to hold additional data other than just column visibility. (Sorting preferences or similar). Just make sure the top level property is set to private.

> [@Save/restore component properties to DB](https://forum.inductiveautomation.com/t/save-restore-component-properties-to-db/88383/9):
>
> Correct. To make it sticky, save/load from the DB. I'd say this is much easier and more transparent than diving into using SDK functions, especially if you get another engineer who knows nothing about the project/customization data. (That's my opinion anyways). It would also essentially 'live' in only one or two places, the session startup handler and the user id value change event, as opposed to every component that needed some sort of customization. You could have a structure something alo…

One pitfall I could see is if a single table is used for different queries, you could run into a case where column A needs to be hidden for query A, but should be shown for query B. That means you might need to include additional identifier information in your config data to indicate if the column visibility is for the table in general or a specific query on that table.

> [@Farhan\_Basheer](#):
>
> onEditCellCommit

Writing directly to the session props could leave you with orphaned key/value pairs if you change what columns are available for the table after saving a config, but that's a pretty negligible cost unless you have thousands of orphaned items. You could also run a cleanup operation on the storage table if you really needed/wanted to clean out stale keys.

> [@Farhan\_Basheer](#):
>
> A helper function

Are you able to modify your existing function that generates your columns to take an optional `userConfig` argument and pass the config for the table through that?

Then when you are doing whatever logic to loop through and create the columns, you can check immediately to see if the column should be hidden or not. This would save you from looping over the list of columns again after their generation.

I would still keep the helper for any post generation changes. On submission of new config, pass the existing generated columns, new config, and table Id, and adjust the columns based on the new config.

---

<div class="post-metadata">

**Author:** ![Farhan\_Basheer](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/farhan_basheer/32/66759_2.png) [@Farhan\_Basheer](https://forum.inductiveautomation.com/u/Farhan_Basheer)\
**Post date:** [March 6, 2026, 6:07pm UTC](https://forum.inductiveautomation.com/t/architecting-a-centralized-column-visibility-manager-for-dynamic-perspective-tables/114352/3 "2026-03-06T18:07:36Z")

</div>

Thanks for the detailed feedback! You hit on a few points I hadn't fully considered yet—specifically the `Query-specific identifier` and the potential for orphaned keys.

Based on your suggestions, here is my updated plan:

1. **Query-ID Logic:** I’ll move away from using just the `Table.name` as the key. I'll pass a specific `configId` (e.g., `Overview_Alarms` vs `Overview_History`) to the generation script. This ensures the same physical table component can hold different visibility states depending on the data it's currently displaying.
2. **Single-Loop Optimization:** I'm refactoring my `generateColumns` function to accept the `sessionPrefs` as an optional argument. This allows me to set the `visible` property and skip unnecessary width calculations for hidden columns in a single pass, rather than looping over the column list twice.
3. **Sticky Persistence:** I'll take your advice on using the Session Startup/Shutdown handlers to load/save the JSON from a DB. It seems much cleaner than trying to manage it on every single view.
4. **Orphaned Keys:** I agree the overhead is negligible. I’ll just ensure my `Column Manager` popup only builds its UI based on the `availableColumns` actually present in the current dataset, which effectively ignores any stale keys in the session dictionary.

I appreciate the tip on setting the session property to private—definitely a 'best practice' I'll be following. Thanks again for the sanity check!
