Fixed: Pass config down through DispatchRenderer.vue

So this is the scenario (snippet)

We have a schema

"Parent": {
    "type": "array",
    "title": "Parent title",
    "options": {
      "sortable": true
    },
    "items": {
      "type": "object",
      "properties": {
        "document": {
          "type": "string",
          "description": "description",
          "title": "document. title",
          "oneOf": [
            {
              "const": "FIRST",
              "title": "First item"
            },
            {
              "const": "SECOND",
              "title": "second item"
            }
          ]
        },
        "anotherDocument": {
          "type": "string",
          "description": "description",
          "title": "another title",
          "oneOf": [
            {
              "const": "THIRD",
              "title": "third title"
            },
            {
              "const": "FOURTH",
              "title": "fourth title"
            }
          ]
        }
      }
    }
  }

A uischema

 {
  "type": "VerticalLayout",
  "elements": [
    {
      "type": "Control",
      "scope": "#/properties/Parent",
      "options": {
        "detail": {
          "type": "HorizontalLayout",
          "elements": [
            {
              "type": "Control",
              "scope": "#/properties/document"
            },
            {
              "type": "Control",
              "scope": "#/properties/antherDocument"
            }
          ]
        }
      }
    }
  ]
}

(I created a snippet of the schema and uischema, any scope or names that seem incorrect are probably typos in making it a generic example).

With our system setup, this is then run through our renderer tester, and for the first level, we load a so called ‘Array List’ renderer (which is customized), but basically, renders rows (and there are options to sort). The children are then rendererd, one by one, through a default <dispatch-renderer> which decides on what renderer to use. Then for every step, it will also apply the ControlWrapper.

This is where we run into a ‘problem’.

What we want, is to render the label as you would see with a table head. (this works, not that hard, loop in the parent through the control.schema.properties).

But now, these children within the rows, they have their labels rendered per element. And, basically, we want to pass a boolean value to the Control Wrapper (or an options object), where we can do that.

But, and yes we might miss things here, it seems that in the dispatch renderer, any customizations are not taking into account, tried to update the ‘appliedOptions’, tried using a config prop on the DispatchRenderer (which is read). But can’t seem to get the right value on the right level.

Other approaches i have thought of (and maybe discarded).

  • Just use CSS to hide the labels of the children → yes! would be so easy! might just do that eventually
  • create a custom DispatchRenderer.vue → done that to test out a few things, seems like it would be an option, but rather stay clear from that.
  • some convoluted way of using inject and checking parent / child relationships
  • add it to the uischema → we have all the different possible scenarios of forms and (ui)schemas, where people creating these need not to think about the visual end result.

Fix:

So the easy solution was actually to use the provide / inject mechanism that Vue offers.
The Parent (Array List) provides showLabel: false. In the ControlWrapper i inject the showLabel property (set it to true as a default for when there is no value).

This way an item using the ControlWrapper that is not a direct ‘child’ of the ArrayList will not get that value injected and thus show the label. Otherwise it is overriden.

Next step would be to solve it in Make ControlWrapper configurable in vue-vanilla · Issue #1927 · eclipsesource/jsonforms · GitHub

Hi @richardj,

Yes, using the built-in mechanism of React, Angular and Vue is an easy way of sharing data between your renderers.

In theory we could also enable passing props directly through dispatching. At the moment all additional props given to the dispatcher are ignored here in the core mappers, which makes sense.

However the dispatcher itself could pass any additional props through to the rendered component, so instead of just passing the props of the mapping, all normal props could be passed here as well. The additional props would then be available in the props of the dispatched to element.

I tried to test out that theory, to pass those props down, but they did not seem to be picked up by the DispatchRenderer.vue. I might fiddle with the approach a little bit in the future (as we will be expanding a lot with different custom renderers and long and complex forms).

Should those props (in DispatchRenderer.vue) be combined with the renderer that is then bound?

<component :is=“determinedRenderer” v-bind=“renderer”>

Hi @richardj,

Yes they need to be passed together then. At the moment only the props coming back from the mapper are placed in renderer. Also when combining, they must be combined with the correct priority, i.e. the props defined in renderer must win against the regular props.

For example we could adapt

  setup(props) {
    return useJsonFormsRenderer(props);
  },

to

  setup(props) {
    const result = useJsonFormsRenderer(props);
    return {
       renderer: {  ...props, ...result.renderer }
    };
  },

This then must be checked for correctness and whether reactivity works as intended or need some further minor tweaks.