Null properties error when using findUISchema in custom object renderer

Hello,

I have a custom vanilla vue 2 nested object renderer similar to the vuetify example.

I am getting an error in my computed property that uses findUISchema:

"[native Error Cannot set properties of null (setting 'label')<>TypeError: Cannot set properties of null (setting 'label')\n    at VueComponent.detailUiSchema (webpack-internal:///./node_modules/babel-loader/lib/index.js?!./node_modules/ts-loader/index.js?!./node_modules/vue-loader/lib/index.js?!./node_modules/unplugin/dist/webpack/loaders/transform.js?!./src/components/jsonforms/ObjectRenderer.vue?vue&type=script&lang=ts&:58:22)\n    at Watcher.get (webpack-internal:///./node_modules/vue/dist/vue.common.dev.js:4490:25)\n    at Watcher.evaluate (webpack-internal:///./node_modules/vue/dist/vue.common.dev.js:4592:21)\n    at VueComponent.computedGetter [as detailUiSchema] (webpack-internal:///./node_modules/vue/dist/vue.common.dev.js:4843:17)\n    at processComputed (chrome-extension://nhdogjmejiglipccpnnnanhbledajbpd/build/backend.js:4190:24)\n    at getInstanceState (chrome-extension://nhdogjmejiglipccpnnnanhbledajbpd/build/backend.js:3925:116)\n    at getInstanceDetails (chrome-extension://nhdogjmejiglipccpnnnanhbledajbpd/build/backend.js:3910:12)\n    at chrome-extension://nhdogjmejiglipccpnnnanhbledajbpd/build/backend.js:5231:60\n    at DevtoolsHookable.callHandlers (chrome-extension://nhdogjmejiglipccpnnnanhbledajbpd/build/backend.js:745:17)\n    at DevtoolsApi.callHook (chrome-extension://nhdogjmejiglipccpnnnanhbledajbpd/build/backend.js:227:29)]"

Here is the object renderer:

<template>
  <div v-if="control.visible">
    <DispatchRenderer
      :visible="control.visible"
      :enabled="control.enabled"
      :schema="control.schema"
      :uischema="detailUiSchema"
      :path="control.path"
      :renderers="control.renderers"
      :cells="control.cells"
    />
  </div>
</template>

<script lang="ts">
import type {
  ControlElement,
  JsonFormsRendererRegistryEntry,
  UISchemaElement,
} from '@jsonforms/core'
import { findUISchema, rankWith, scopeEndsWith } from '@jsonforms/core'
import type { RendererProps } from '@jsonforms/vue2'
import {
  DispatchRenderer,
  rendererProps,
  useJsonFormsControlWithDetail,
} from '@jsonforms/vue2'
import isEmpty from 'lodash/isEmpty'
import { defineComponent } from 'vue-demi'

const controlRenderer = defineComponent({
  components: {
    DispatchRenderer,
  },
  props: {
    ...rendererProps<ControlElement>(),
  },
  setup(props: RendererProps<ControlElement>) {
    return useJsonFormsControlWithDetail(props)
  },
  computed: {
    detailUiSchema(): UISchemaElement {
      const result = findUISchema(
        this.control.uischemas,
        this.control.schema,
        this.control.uischema.scope,
        this.control.path,
        'Group',
        this.control.uischema,
        this.control.rootSchema
      )

      if (isEmpty(this.control.path)) {
        result.type = 'VerticalLayout'
      } else {
        ;(result as any).label = this.control.label
      }

      return result
    },
  },
})

export default controlRenderer

export const entry: JsonFormsRendererRegistryEntry = {
  renderer: controlRenderer,
  tester: rankWith(1000, scopeEndsWith('question')),
}
</script>

And here are my schemas:

{
  "question": {
    "type": "object",
    "properties": {
      "id": {
        "type": "integer"
      },
      "text": {
        "type": "string"
      },
      "plainEnum": {
        "type": "string",
        "enum": ["foo", "bar", "foobar"]
      }
    }
  }
}
{
  "type": "Control",
  "scope": "#/properties/question",
  "elements": [
    {
      "type": "Control",
      "scope": "#/properties/plainEnum"
    },
    {
      "type": "Control",
      "scope": "#/properties/text"
    }
  ]
}

Any guidance on what is the issue with detailUISchema computed would be greatly appreciated.

Thanks

Hi @jtbradley,

It seems that findUiSchema returns null for you which should not be the case. Can you debug into findUISchema and check why this happens? From a first glance your code looks fine.

Note that your UI Schema is not valid. We don’t allow elements on type: 'Control'. If you want to inline define a UI Schema for the object you need to use options.detail, e.g.

{
  "type": "Control",
  "scope": "#/properties/question",
  "options": {
    "detail": {
      "type": "VerticalLayout",
      "elements": [
          {
            "type": "Control",
            "scope": "#/properties/plainEnum"
          },
          {
            "type": "Control",
            "scope": "#/properties/text"
          }
      ]
    }
  }
}

My first instinct is that the invalid UI Schema should not have an effect but maybe there is some code checking for elements and this is why the findUiSchema breaks. Therefore I would like to suggest to first try it again with a valid UI Schema.

Your JSON Schema listing is probably just an excerpt? If it isn’t you need to wrap the question within a type: 'object' element.

Thanks for your response @sdirix ,

Your UI schema with detail option has fixed the issue.

My last question:

Just to clarify, this object renderer should allow me to render controls that are nested in objects, such as a custom enum control using useJsonFormsEnumControl, correct?

I assume this is the case, as this seems to be the only way I would have access to the enum control.options array. They’re currently not rendering, not sure my assumptions are correct.

Hi @jtbradley,

Yes this object renderer just dispatches back to JSON Forms without any special behavior, so the rendered layout for the object behaves exactly the same as the rest of JSON Forms.

Note that you don’t even need to define a options.detail UI Schema in case it’s not special. findUiSchema will generate a default Ui schema if there is none defined otherwise.

If you like and have some time you can also contribute this object renderer back to the JSON Forms project.

1 Like

Many thanks @sdirix,

Yes, I’d be happy to contribute.