Root OneOf Renderer

I have a schema that has a conditional subschema called ‘config’ based on a dataset ‘type’. Following advice from other posts on the forum I have restructured if/then stanzas in my schema to a oneOf but

First, similar to described here. However this gives a ‘no applicable renderer found’ even if I explicitly specify a oneOfControl variant for the tester. The issue is not the renderer as I am using a variant of vue-vanilla renderers that works in a subsequent example.

 {
                      "type": "Control",
                      "scope": "#/oneOf",
                      "options": {
                          "readonly": false,
                          "variant": "oneOfControl",

                      },
                  },

Second, I followed the second suggestion of using UISchema rules. I have the following under the scope of #/properties:

"type": {
  "title": "Dataset type",
  "enum": [ "DATASET_TYPE1", "DATASET_TYPE2", "DATASET_TYPE3", "DATASET_TYPE4", "DATASET_TYPE5"]
},
"config": {
  "oneOf": [
      {
          "$ref": "#/$defs/dataset1"
      },
      {
          "$ref": "#/$defs/dataset2"
      },
      {
          "$ref": "#/$defs/dataset3"
      },

      {
          "$ref": "#/$defs/dataset4"
      },
      {
          "$ref": "#/$defs/dataset5"
      }
  ]
}

And a UISchema to conditionally display

    {
                            "type": "Group",
                            "elements": [
                                {
                                    "type": "Control",
                                    "label": "Dataset 1 Config",
                                    "scope": "#/properties/config/oneOf[0]",
                                    "rule": {
                                        "effect": "SHOW",
                                        "condition": {
                                            "scope": "#/properties/type",
                                            "schema": {
                                                "const": "DATASET_TYPE1"
                                            }
                                        }
                                    }
                                }
                            ]
                        }

but get a syntax error

SyntaxError: Identifier 'schema1' has already been declared

Finally, the closest to my result is emulating the vuetify oneOf-tab example by nesting the oneOf under an object property like so.

   "type": {
            "oneOf": [
                {
                    "title": "DATASET_1",
                    "type": "object",
                    "properties": {
                        "type": {
                            "const": "DATASET_1"
                        },
                        "config": {
                            "$ref": "#/$defs/dataset1"
                        }
                    }
                },
]}

And this renders as expected but as it is a nested property, no longer binds with form data. Based on these

  1. Is there a correct way to declare a oneOf control in the UISchema (that is not nested under a property)?
  2. Am I missing a ‘correct’ syntax for displaying an indexed item in the oneOf?
  3. If I must nest the oneOf, is there a way to specify what data to bind to (e.g., the “type” and “config” properties under “type” should bind to root level data)?

Hi @andperks ,
our workload is currently quite high and we do not have time to investigate this. We will come back to your questions later though :slight_smile:

Until then, I have one question: Is there some property or anything else named schema1 in you schema or UI Schema. I ask because it’s mentioned in the syntax error.

Best regards,
Lucas

Hi @andperks,

This is not a valid JSON Pointer, you should try #/properties/config/oneOf/0

Is this an error coming from AJV?

The structure is not fully correct here. You had type/config as siblings in the original. So you should move the oneOf one level higher and remove the root config. Regarding the non-binding: We don’t handle the atttributes which just consists of a const that well as they typically don’t make sense for a form.

Generally speaking all of these structures should work. Note that you also always have the option to write a custom renderer specialized for your used structures in the JSON Schema so you can add exactly the behavior you need. For example the const property of the last example could be nicely supported by a custom oneOf renderer which then automatically sets this property when needed. You don’t have to create a custom renderer, however for example maintaining a lot of UI Schema rules also comes with a cost.

Thanks for the response, I was able to resolve this by

  1. moving the oneOf to the root level
  2. forcing the OneOfRenderer by creating a ‘OneOfControl’ variant tester
  3. before calling createCombinatorRenderInfos in the renderer, checking if this.control.schema.oneOf is defined before passing. I think the core issue here is when a OneOf is nested in the root level of a schema (or maybe specified in the UISchema like #/oneOf ), the schema that is passed to the renderer is not longer nested under this.control.schema.oneOf

Still working on how to identify the default index to render as indexOfFittingSchema always appears undefined but I consider this solved.

In case it helps anyone else, I’ll leave context on the issue with conditional visibility rules in the UISchema below:

Ah I was only following the syntax in this thread. I did try using the valid pointer #/properties/config/oneOf/0 but received the same syntaxError. It does appear to be an error from AJV but removing $id from the schema did not solve the issue. Here is the relevant part of the stack trace:

compileSchema	@	index.ts:171
_compileMetaSchema	@	core.ts:744
_compileSchemaEnv	@	core.ts:732
getSchema	@	core.ts:536
defaultMeta	@	ajv.ts:30
validateSchema	@	core.ts:509
_addSchema	@	core.ts:721
compile	@	core.ts:384
validate	@	core.ts:361
evaluateCondition	@	runtime.ts:82
isRuleFulfilled	@	runtime.ts:96
evalVisibility	@	runtime.ts:105
isVisible	@	runtime.ts:166
mapStateToControlProps	@	renderer.ts:459
mapStateToControlWithDetailProps	@	renderer.ts:707
(anonymous)	@	jsonFormsCompositions.ts:174
run	@	reactivity.esm-bundler.js:178
get value	@	reactivity.esm-bundler.js:1147
useVanillaControl	@	composition.ts:45
setup	@	ObjectRenderer.vue:45

Hi @andperks,

Are you sure there is no id or $id property in your JSON Schema left? You can also hand over a custom instance of AJV to JSON Forms in which the whole id checking is disabled.

If you can avoid calling createCombinatorRenderInfos, then please do so. In there we validate all the sub schemas to maybe determine which one fits to the data presented. If your data contains some unique property on which you can decide which sub schema (i.e. index) shall be used, then implement this manually. This will avoid the need of compiling and validating sub schemas, saving a lot in initial rendering performance.