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:

  • I copied the ArrayListRenderer.vue and ArrayListElement.vue from vue-vanilla (https://github.com/eclipsesource/jsonforms/tree/master/packages/vue/vue-vanilla/src/array) to my components folder
  • I adapted the import paths
  • I adapted the templates to reflect the structure of the accordion (see below)
  • I import the renderer component into my view and add it to the vanilla renderers, and added all renderers to the data attribute of my SFC to use it in the template (see below)

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!