How to synchronise custom written filters?

What is the best approach to synchronise custom written filters between multiple filter viewers?

My current approach would be to use grok.events to synchronise the filter value on change. However this approach does not work on fresh initialisation of filter where I would need the value of the already applied filter.

Is there some sort of an API to get the filter value from other filters or how did you solve that with native Datagrok filters?

We currently use combination of events for synchrinization and saving state while filtering to dataFrame to init new viewers from this state.

In native grok we use event ‘d4-filter-criteria-changed’ for notifying other filters and

dataFrame.rows.filterStates

for saving filter’s state.
This array is emptied before each call of onRowsFiltering and filters add their states to it while filtering.

eg.

subs.add(dataFrame.onRowsFiltering.listen((dynamic requester) {

filter.beginUpdate();

// filtering

filter.endUpdate(requester: this);

dataFrame.rows.filters.add("${valueColumn.name}: $filterSummary");
dataFrame.rows.filterStates.add(saveState());

then during filter init check dataFrame.rows.filterStates for state with corresponding column.

var state = dataFrame.rows.filterStates.firstWhere((d) => d[‘column’] == filterColumn.name, orElse: () => null);

if you use filter only whithin native grok places (filter panel and property panel) then Datagrok will automatically find and apply state(you still need to save state, check RowList_AddFilterState method).

Otherwise if you use it as viewer in other places you will need to add the code above with finding the saved state. Unfortunately we don’t have api for it right now though we will add it in next version. If you need it right now you can use other place for storing state like dataFrame tag.

Also we will add synchronization for substructure filter in next version as an example.

2 Likes

Awesome, thanks for all information. This should help me to adapt our filter and make it fully compatible to your native filter behaviour.

1 Like

@dkryvchuk I gave a spin but was not successfully with sharing the filter state, can you help me out here?

  1. checking: grok.shell.t.rows object does not show a property filterStates. I can only see something like addFilterState (referenced here as well: Class: RowList | Datagrok) but I was not successfully applying and restored filter state.
  2. What is the purpose of filter.beginUpdte() and filter.endUpdate methods? There is no reference in the API docs?
  3. Could you explain the effect of this method: filters.add("${valueColumn.name}: $filterSummary");
  1. Yes, you only need rows.addFilterState method. It will save the filter’s state and next time you open filters panel or reopen filter in property panel, platform will automatically apply it via .applyState() method of your filter.
  2. filter.beginUpdte() and filter.endUpdate methods are used to not notify changes after each single row change in bitset. We start updating by filter.beginUpdte(), modify the bitset and then notify others that we have updated the filter by filter.endUpdate .
  3. filters object is used to store descriptions of currently applied filters. It is not needed for sync but we use it in other places. rows.filters are also cleared before each .requestFilter(), so you should add it in onRowsFiltering method.

I’ve tried to follow your example but was not able to do so.

  1. According the Datagrok API (link: Interface: FilterState | Datagrok, we need to specify an object with type and column but how do I add the filter state (for example entered value)?
  2. Both methods filter.beginUpdate and filter.endUpdate are not specified in my custom filter. Can you share how you define the filter constant in your example?

Would it be possible to share a fully functional code example? This would be super helpful to continue with our custom filter.

Btw: Which Datagrok version do you use?

  1. State is just an ordinary JS Object. You can add in it everything you want. The way it is used in substructure filter

    this.dataFrame?.rows.addFilterState(this.saveState());
    saveState(): any {
    const state = {
    column: this.columnName,
    columnName: this.columnName
    };
    state.type = ‘Chem:substructureFilter’;
    state.molBlock = this.sketcher.getMolFile();
    return state;
    }

  2. sorry, filter.beginUpdate and filter.endUpdate are our internal methods, in js-api use

this.dataFrame?.filter.set (notify: false) and then FireChanged, method in the end of filtering or use own Bitset for filter and then use this.dataFrame?.filter.and(this.bitset); in the while filtering dataset.

I am sorry but you’re suggestions don’t work with my Grok version. My code seems to successfully store the filter state (no error on rows.addFilterState(this.saveState()), however on I don’t get the previous saved filter on applyState.

Is there a fully working example available somewhere to test and play around with this? I would really appreciate having a full working example by hand.

After rows.addFilterState(this.saveState()), everytime you add another same filter platform should trigger applyState() with state stored. applyState() you need to implement yourself for filter. Does applyState not have as argument the stored state when opening new instance? make sure you have rows.addFilterState(this.saveState()) in method that filters rows. Also it only works so far in filters panel and property panel.
As for example, you can check our substructure filter

Also, if needed I can create simpler example or maybe you can write me and I will look on issue you are facing.

1 Like