Build custom JavaScript filter using native filter UI elements

Is there a way to build a custom JavaScript filter and combining it with the default filter UI used for all other fitlers? We would be mainly interested in having a special filter based on a textarea which should have the native look & feel like the others (e.g. allow quick enable/disable, reset etc.)

Example UI elements we would be interested in.

It seems like this isn’t fully supported currently. I tried on a custom filter from the Widgets package. From the listed components, only quick enable/disable and the close icon were added.

Do you plan to add such custom filter to the native filters panel? I’d like to understand the use case a bit more.

We are working on a custom filter for compound & sample ids (using a simple string list pasted to a textarea). It’s nothing super complex but of course super helpful for our user base!

Our requirements are basically:

  1. have a TextArea user can paste list of ids (split by new line)
  2. filter should behave like native filters:
  • store and restore on layout save and restore
  • allow enable/disable like native filters
  • proper reset behaviour (global as well as single filter)
  • etc.
1 Like

Hi @andreas.g.business, yes we support that.

This is what you need: https://datagrok.ai/help/develop/how-to/custom-filters.

@andreas.g.business - the requirements sound pretty generic, would it make sense to implement it within one of the standard plugins, or it is specific to your company?

Hmmm currently it is specific to us (as we use our dedicated tags to identify columns) but I guess this is something which could dynamically bet set on filter initialisation, I guess! That way this filter would be generic and potentially useful for others as well!

For now we will continue with our company specific implementation (to keep our deadlines) but I keep this in mind and will write this filter in way to be moved to open source later on, if this is helpful?

This sounds great - and indeed it would be awesome to have it generalized and made available for everyone :slight_smile:

1 Like

I made great progress during the day but ended with some questions, hopefully you can answer them:

  1. how can I listen and react to native filter events such as reset individual/global filters?
  2. Using the native filter controls, how can I listen and control these elements?

@skalkin Another thing I realised today. Our custom filter works excellent if added through UI or stored layout. However, once we use the provided API method (grok.shell.v.filters({ filters: [{ type: 'Analysis:compoundFilter', columnName: 'Compound Id' }] }) ), the initialisation fails with following error message. Any ideas what’s happening here?

js_helper.dart:1772 
        
       Uncaught TypeError: Cannot read properties of null (reading 'c')
    at bHX.$1 (column.dart:56:22)
    at ar.ah (js_array.dart:318:11)
    at Object.Wr (filter_control.dart:72:21)
    at pq.ajK (filters_core.dart:240:18)
    at pq.t (login.dart.js_1.part.js?79176:18334:29)
    at pq.c7 (filters_core.dart:264:9)
    at dart.bIX.$1 (filters_core.dart:65:7)
    at ddq.H4 (zone.dart:1307:16)
    at d5Q.ay (stream_impl.dart:330:5)
    at dart.o5.kT (stream_impl.dart:257:7)
    at x.ay (broadcast_stream_controller.dart:379:7)
    at dart.xH.t (broadcast_stream_controller.dart:254:5)
    at UE.eval (eval at bgc (js_helper.dart:2942:12), <anonymous>:3:34)
    at ddq.H4 (zone.dart:1307:16)
    at d5Q.ay (stream_impl.dart:330:5)
    at dart.o5.kT (stream_impl.dart:257:7)
    at x.ay (broadcast_stream_controller.dart:379:7)
    at dart.xH.t (broadcast_stream_controller.dart:254:5)
    at UE.eval (eval at bgc (js_helper.dart:2942:12), <anonymous>:3:34)
    at ddq.H4 (zone.dart:1307:16)
    at d5Q.ay (stream_impl.dart:330:5)
    at FM.Mi (stream_impl.dart:579:5)
    at O5.amT (stream_impl.dart:695:5)
    at dart.dd3.$0 (stream_impl.dart:655:7)
    at Object.dTM (schedule_microtask.dart:41:5)
    at dart.fXG (schedule_microtask.dart:50:5)
    at dart.d5a.$1 (async_patch.dart:51:9)
    at fzO.$0 (js_helper.dart:2456:48)
    at NY.L4 (isolate_helper.dart:474:16)
    at Object.G4 (isolate_helper.dart:59:16)
    at dart.fzM (js_helper.dart:2456:14)
    at MutationObserver.<anonymous> (js_helper.dart:2476:14)
u @ js_helper.dart:1772
$0 @ async_patch.dart:577
dTM @ schedule_microtask.dart:41
dart.fXG @ schedule_microtask.dart:50
dart.d5a.$1 @ async_patch.dart:51
$0 @ js_helper.dart:2456
L4 @ isolate_helper.dart:474
G4 @ isolate_helper.dart:59
dart.fzM @ js_helper.dart:2456
(anonymous) @ js_helper.dart:2476
childList (async)
$1 @ async_patch.dart:67
aXJ @ async_patch.dart:28
dart.a2p @ zone.dart:1176
BZ @ schedule_microtask.dart:137
OR @ stream_impl.dart:651
w9 @ stream_impl.dart:317
ay @ stream_controller.dart:811
dart.O4.kT @ stream_controller.dart:667
dart.O4.t @ stream_controller.dart:613
dart.cQI.$1 @ take_until.dart:47
H4 @ zone.dart:1307
ay @ stream_impl.dart:330
dart.o5.kT @ stream_impl.dart:257
kT @ stream_pipe.dart:132
B4 @ stream_pipe.dart:326
dart.NT.aEz @ stream_pipe.dart:164
eval @ VM43576:3
H4 @ zone.dart:1307
ay @ stream_impl.dart:330
dart.o5.kT @ stream_impl.dart:257
ay @ stream_controller.dart:796
dart.O4.kT @ stream_controller.dart:667
$0 @ stream_controller.dart:613
dart.fHD.$1 @ stream.dart:207
dart.cS8.$0 @ isolate_helper.dart:1414
$0 @ js_helper.dart:2454
L4 @ isolate_helper.dart:474
G4 @ isolate_helper.dart:59
dart.fzM @ js_helper.dart:2454
(anonymous) @ js_helper.dart:2476
setInterval (async)
aBv @ isolate_helper.dart:1410
cS7 @ isolate_helper.dart:1406
aTw @ async_patch.dart:129
a8z @ zone.dart:1399
lr @ timer.dart:75
$0 @ stream.dart:206
$0 @ stream.dart:215
Gi @ stream_controller.dart:837
$0 @ stream_controller.dart:713
a67 @ stream_impl.dart:409
a7b @ stream_controller.dart:712
al @ stream_controller.dart:850
bl @ stream_impl.dart:467
ft @ login.dart.js?79176:5383
S6 @ stream_pipe.dart:122
al @ stream_pipe.dart:347
bl @ stream_pipe.dart:86
ft @ login.dart.js?79176:5569
$1 @ take_until.dart:46
$0 @ util.dart:10
Gi @ stream_controller.dart:837
$0 @ stream_controller.dart:713
a67 @ stream_impl.dart:409
a7b @ stream_controller.dart:712
al @ stream_controller.dart:850
bl @ stream_impl.dart:467
ft @ login.dart.js?79176:5383
dart.bJN.$1 @ flat_map.dart:38
H4 @ zone.dart:1307
ay @ stream_impl.dart:330
dart.o5.kT @ stream_impl.dart:257
$1 @ broadcast_stream_controller.dart:387
a5T @ broadcast_stream_controller.dart:328
ay @ broadcast_stream_controller.dart:386
dart.xH.t @ broadcast_stream_controller.dart:254
eval @ VM43630:3
H4 @ zone.dart:1307
ay @ stream_impl.dart:330
dart.o5.kT @ stream_impl.dart:257
ay @ broadcast_stream_controller.dart:379
dart.xH.t @ broadcast_stream_controller.dart:254
dart.aVe.t @ broadcast_stream_controller.dart:480
eval @ VM43637:3
H4 @ zone.dart:1307
ay @ stream_impl.dart:330
dart.o5.kT @ stream_impl.dart:257
ay @ broadcast_stream_controller.dart:379
dart.xH.t @ broadcast_stream_controller.dart:254
eval @ VM43630:3
H4 @ zone.dart:1307
ay @ stream_impl.dart:330
dart.o5.kT @ stream_impl.dart:257
ay @ broadcast_stream_controller.dart:379
dart.xH.t @ broadcast_stream_controller.dart:254
J.ad @ login.dart.js?79176:18202
a8 @ event_bus.dart:69
bz @ login.dart.js_1.part.js?79176:63168
dart.pq.aD @ filters_core.dart:303
dart.pq.aD @ login.dart.js_1.part.js?79176:18373
fi @ filters_core.dart:215
saj @ data_frame_viewer.dart:68
ann @ viewer_descriptor.dart:61
aw @ login.dart.js_1.part.js?79176:16722
dart.dxk.$2 @ table_view.dart:726
fS @ js_helper.dart:1521
dart.dhd @ js_helper.dart:1489
(anonymous) @ js_dart2js.dart:667
addViewer @ view.ts:404
filters @ view.ts:497
openFilter @ index.js:99
_callee3$ @ index.js:178
tryCatch @ regeneratorRuntime.js:44
(anonymous) @ regeneratorRuntime.js:125
(anonymous) @ regeneratorRuntime.js:69
asyncGeneratorStep @ asyncToGenerator.js:3
_next @ asyncToGenerator.js:22
(anonymous) @ asyncToGenerator.js:27
(anonymous) @ asyncToGenerator.js:19
init @ index.js:186
addNewTab @ ViewManager.js:121
(anonymous) @ Portal.jsx:74
onClick @ index.jsx:119
callCallback @ react-dom.development.js:188
invokeGuardedCallbackDev @ react-dom.development.js:237
invokeGuardedCallback @ react-dom.development.js:292
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:306
executeDispatch @ react-dom.development.js:389
executeDispatchesInOrder @ react-dom.development.js:414
executeDispatchesAndRelease @ react-dom.development.js:3278
executeDispatchesAndReleaseTopLevel @ react-dom.development.js:3287
forEachAccumulated @ react-dom.development.js:3259
runEventsInBatch @ react-dom.development.js:3304
runExtractedPluginEventsInBatch @ react-dom.development.js:3514
handleTopLevel @ react-dom.development.js:3558
batchedEventUpdates$1 @ react-dom.development.js:21871
batchedEventUpdates @ react-dom.development.js:795
dispatchEventForLegacyPluginEventSystem @ react-dom.development.js:3568
attemptToDispatchEvent @ react-dom.development.js:4267
dispatchEvent @ react-dom.development.js:4189
unstable_runWithPriority @ scheduler.development.js:653
runWithPriority$1 @ react-dom.development.js:11039
discreteUpdates$1 @ react-dom.development.js:21887
discreteUpdates @ react-dom.development.js:806
dispatchDiscreteEvent @ react-dom.development.js:4168

Reported in https://github.com/datagrok-ai/public/issues/1371. We’ll investigate the issue and post an update in this topic once it gets fixed.

This is fixed in v 1.12.0