Patterns and Practices: Creating a custom renderer to interactively select data from a remote source

We have started a proof of concept of the following pattern, and are wondering if we are on the right track:

jsonSchema:

Define an object with sufficient metadata to:

  • connect to a remote data source path and auth,
  • describe the remote entity array to be retrieved,
  • the remote entity property to show in a drop-down-control, and
  • the entity properties that need to be serialized in the jsonData after a selection is made.

(JsonRef is insufficient for this, so we are extending jsonSchema7 to support the new metadata entries.)

Add each of the entity properties we want to save to the jsonSchema with names like [entityName][PropertyName]

uiSchema:

We add a control pointing to our custom schema object, and controls for each of the [entityName][PropertyName] values we want to show the user after they’ve made a selection.

Renderers and Controls:

Create and register a custom renderer to interact with the data-source API (using search queries, filtering, and paging), it is a drop down with async support.

On selection of an entity, we are doing the following:

  • jsonFormsService.getState().jsonforms.core.data to get the current root-level jsonData
  • appending each of our new [entityName][PropertyName]: selection.PropertyName
  • writing this into: jsonFormsService.setData(newRootData)

Discarded ideas:

We thought about using a resolver, but didn’t find a clean way of interacting with the ui user: taking in a query string, including debouncing typed input, showing results as they come in, etc.

Using jsonRef to specify all the metadata. We just couldn’t get all the props in there, including the array of strings needed to enumerate the remote properties we want to retain. Extensibility was a problem and ultimately using jsonRefs here just pushed us towards a resolver pattern (with the problems mentioned above).

Your thoughts?

Are we headed for trouble? Have you seen anyone go down this path, is there a better pattern or extension point?

Hi @NickDrouin,

This sort of use case is very common. JSON Forms is often used for UIs which manage a lot of data, so some sort of remote backed data source often needs to be supported.

Now, if I understand correctly, then you

  • enrich a type: object JSON Schema object with some remote data source information
  • at runtime, the instance data of this object can be filled with arbitrary many properties with data coming in from the remote source
  • the data coming in from the data source is “read-only”, i.e. afterwards not edited by the user (besides maybe switching to another entry).

My remarks:

  • If the properties are actually read only then I don’t think any UI Schema manipulation is necessary. In that case just embed all the logic in this one custom object renderer and handle everything within it
  • If the properties are actually editable and maybe you also hand over schemas and uischemas with your data source, then I would think about not implementing this in JSON Forms at all. This then rather looks like it should be a standalone Angular component which handles the overall data source manipulation and just leverages JSON Forms for each of the detail views.

This seems a bit weird to me. I would have expected that in your custom object renderer you would only modify the object instance data itself and not the root data. What you suggest would only make sense if the only special custom object is the root object. However if that is the case I would think about what the benefit of solving this use case within JSON Forms is at all and why not a regular Angular component is used which just leverages JSON Forms for each of the entity details (same critique as above).

Let me know whether I understood your use case correctly and whether you have additional questions

1 Like

Thanks for your reply. We did get the PoC working, but when looking at some of our other use-cases, we realized we also needed multi-select of remote data, which meant serializing the user-selections as an array. This complicated how to manage the re-write at the root.

So, instead, we have moved things around a bit and have settled on:

All the remote source metadata (path and jsonPath within the response, and what subset of the remote object gets saved back into the jsonData); and all the selection rendering options: single or multi-select and dropdown or table-view — will go into uiSchema.options. This allows us to use Tester.optionIs() to select the correct renderer.

The jsonSchema is as-expected, an object (or array) with whatever properties we are filtering down to (for use in other jsonForms controls).

The jsonData is simply the object or array, at whatever level it is in the jsonSchema.

That is, everything is encapsulated withing the uiSchema.options for setting up the custom renderer/data-selector.

The main driver for this decision is that we needed to set options specific to the rendering of the remote data, and if felt odd to be using metadata in the jsonSchema instead of the uiSchema – we now have the slightly less awkward scenario of connection data in the uiSchema, but that metadata is consumed by the ui control, so I’m a bit more comfortable with that.

Thank you for taking the time to answer here, and within GitHub where we found other such responses that led us to this design.

Hi @NickDrouin,

I see! Yes, if the additional information is not strictly tied to the data itself but is more related to the visual representation, then enhancing the UI Schema makes a lot of sense!