Customize Array control to render UIKit accordion

Hi group,

I am looking to customize the Array Control to render it’s elements as an UIKit accordion (Accordion - UIkit) in a vue3 app. I keep getting a runtime error and would like to pick your brains about it.

Here’s my thinking:

  • I am creating a VUE app and get jsonforms, jsonforms-vue and jsonforms-vue-vanilla up and running in v3.0.0-beta.5
  • I define custom styles and have them applied to match the rest of my UIKit app interface
  • I copy the Array control into my components, customize it as needed, add it to the render registry
  • BAM! Customized jsonforms in the blink of an eye

We all know this did not happen as planned. So here’s what I have so far:

ArrayListRenderer.vue - template

<template>
  <fieldset v-if="control.visible" :class="styles.arrayList.root">
    <legend :class="styles.arrayList.legend">
      <button
        :class="styles.arrayList.addButton"
        @click="addButtonClick"
        type="button"
      >
        +
      </button>
      <label :class="styles.arrayList.label">
        {{ control.label }}
      </label>
    </legend>
    <ul uk-accordion="multiple: true">
      <array-list-element
        :moveUp="moveUp(control.path, index)"
        :moveUpEnabled="index > 0"
        :moveDown="moveDown(control.path, index)"
        :moveDownEnabled="index < control.data.length - 1"
        :delete="removeItems(control.path, [index])"
        :label="childLabelForIndex(index)"
        :styles="styles"
        v-for="(element, index) in control.data"
        :key="`${control.path}-${index}`"
      >
        <dispatch-renderer
          :schema="control.schema"
          :uischema="childUiSchema"
          :path="composePaths(control.path, `${index}`)"
          :enabled="control.enabled"
          :renderers="control.renderers"
          :cells="control.cells"
        />
      </array-list-element>
    </ul>
    <div v-if="noData" :class="styles.arrayList.noData">No data</div>
  </fieldset>
</template>

ArrayListElement.vue - template

<template>
  <div :class="styles.arrayList.item">
    <div @click="expandClicked" :class="toolbarClasses">
      <div :class="styles.arrayList.itemLabel">{{ label }}</div>
      <button
        @click="moveUpClicked"
        :disabled="!moveUpEnabled"
        :class="styles.arrayList.itemMoveUp"
        type="button"
      >
        ↑
      </button>
      <button
        @click="moveDownClicked"
        :disabled="!moveDownEnabled"
        :class="styles.arrayList.itemMoveDown"
        type="button"
      >
        ↓
      </button>
      <button
        @click="deleteClicked"
        :class="styles.arrayList.itemDelete"
        type="button"
      >
        🗙
      </button>
    </div>
    <div :class="contentClasses">
      <slot></slot>
    </div>
  </div>
</template>

Adding ArrayListRenderer to VanillaRenderer

import { vanillaRenderers } from "@jsonforms/vue-vanilla";

import ArrayListRenderer from "@/components/jsonforms/ArrayListRenderer.vue";

vanillaRenderers.push(ArrayListRenderer);
const jfRenderers = Object.freeze(vanillaRenderers);

...
data() {
    return {
      form: null,
      editform: false,
      data: null,
      jfRenderers,
      jfSchema,
      jfUiSchema,
    };
  },
...

I can serve the app, but when I render the form I get this error message in the console, and the form doesn’t render:

Since I haven’t modified any of the defineComponent()-code, I don’t understand how I can get this error. jsonforms is running with no errors without my custom control, so I excluded a beta-issue for now.

Thanks for all your help!

So, it was all there in the FAQ :confused: Just needed to be more focused. I will document it here for others since the official documentation is react-focused. (Maybe this example will find its way into the official docu for vue-folks like me).

The Renderer has two exports:

  • default = Component
  • entry = RendererRegistryEntry holding the component and the tester

Since the registry entry needs both, the component and the tester, the Import into my View needed a simple change (see below).

to

import { entry as ArrayListRenderer } from "@/components/jsonforms/ArrayListRenderer.vue";

All that‘s left now is to set the rank to 3, so the custom renderer is always picked instead of the default vanillaRenderer.

1 Like

Hi @kimamil,

Thanks for the great write up! Glad that you were able to fix it yourself!