Hi @sdirix thank you for the insight.
I first solved it with a custom event, emitted from the array-list-element (see the ‘@duplicate’ listener on the) component, using the ‘addItem()’ wrapper function for the update dispatch.
<template>
<fieldset v-if="control.visible" :class="styles.arrayList.root">
<label v-if="control.label" class="uk-form-label uk-text-primary">{{
control.label
}}</label>
<ul
v-if="!noData"
:class="styles.arrayList.itemWrapper"
uk-accordion="multiple: true"
>
<array-list-element
v-for="(element, index) in control.data"
:moveUp="moveUp(control.path, index)"
:moveUpEnabled="index > 0"
:moveDown="moveDown(control.path, index)"
:moveDownEnabled="index < control.data.length - 1"
@duplicate="duplicateItem(index)"
:delete="removeItems(control.path, [index])"
:label="childLabelForIndex(index)"
:styles="styles"
:key="`${control.path}-${index}`"
:initiallyExpanded="uischema.options?.detail.initiallyExpanded"
>
<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-else :class="styles.arrayList.noData">No Items</div>
<a
href="#"
class="uk-button uk-button-small uk-button-secondary"
@click.prevent="addButtonClick"
>Add an Item</a
>
<hr />
</fieldset>
</template>
<script lang="ts">
import {
composePaths,
createDefaultValue,
ControlElement,
moveDown,
moveUp,
} from "@jsonforms/core";
import { defineComponent } from "vue";
import {
DispatchRenderer,
rendererProps,
useJsonFormsArrayControl,
RendererProps,
} from "@jsonforms/vue";
import { useVanillaArrayControl } from "@jsonforms/vue-vanilla";
import ArrayListElement from "./ArrayListElement.vue";
const controlRenderer = defineComponent({
name: "array-list-renderer",
components: {
ArrayListElement,
DispatchRenderer,
},
props: {
...rendererProps<ControlElement>(),
},
setup(props: RendererProps<ControlElement>) {
return useVanillaArrayControl(useJsonFormsArrayControl(props));
},
computed: {
noData(): boolean {
return !this.control.data || this.control.data.length === 0;
},
},
methods: {
composePaths,
createDefaultValue,
addButtonClick() {
this.addItem(
this.control.path,
createDefaultValue(this.control.schema)
)();
},
moveDown,
moveUp,
duplicateItem(index: number) {
this.addItem(this.control.path, { ...this.control.data[index] })();
},
},
});
export default controlRenderer;
</script>
While this works, I am eager to solve it with the same pattern as the moveUp method. But I am stuck with a ‘this context’ issue:
- With options api, injected variables are accessible via “this”
- To use the pattern of the moveUp function, I think I need to return an unnamed function
- the unknown function however, doesn’t know the vue components “this” context
<template>
<fieldset v-if="control.visible" :class="styles.arrayList.root">
<label v-if="control.label" class="uk-form-label uk-text-primary">{{
control.label
}}</label>
<ul
v-if="!noData"
:class="styles.arrayList.itemWrapper"
uk-accordion="multiple: true"
>
<array-list-element
v-for="(element, index) in control.data"
:moveUp="moveUp(control.path, index)"
:moveUpEnabled="index > 0"
:moveDown="moveDown(control.path, index)"
:moveDownEnabled="index < control.data.length - 1"
:duplicate="duplicateItem(control.path, control.data[index])"
:delete="removeItems(control.path, [index])"
:label="childLabelForIndex(index)"
:styles="styles"
:key="`${control.path}-${index}`"
:initiallyExpanded="uischema.options?.detail.initiallyExpanded"
>
<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-else :class="styles.arrayList.noData">No Items</div>
<a
href="#"
class="uk-button uk-button-small uk-button-secondary"
@click.prevent="addButtonClick"
>Add an Item</a
>
<hr />
</fieldset>
</template>
<script lang="ts">
import {
composePaths,
createDefaultValue,
ControlElement,
moveDown,
moveUp,
Actions,
} from "@jsonforms/core";
import { defineComponent, inject } from "vue";
import {
DispatchRenderer,
rendererProps,
useJsonFormsArrayControl,
RendererProps,
} from "@jsonforms/vue";
import { useVanillaArrayControl } from "@jsonforms/vue-vanilla";
import ArrayListElement from "./ArrayListElement.vue";
const controlRenderer = defineComponent({
name: "array-list-renderer",
components: {
ArrayListElement,
DispatchRenderer,
},
props: {
...rendererProps<ControlElement>(),
},
setup(props: RendererProps<ControlElement>) {
return useVanillaArrayControl(useJsonFormsArrayControl(props));
},
inject: ["dispatch"],
computed: {
noData(): boolean {
return !this.control.data || this.control.data.length === 0;
},
},
methods: {
composePaths,
createDefaultValue,
addButtonClick() {
this.addItem(
this.control.path,
createDefaultValue(this.control.schema)
)();
},
moveDown,
moveUp,
duplicateItem: (path: string, value: any) => () => {
this.dispatch(Actions.update(path, value));
},
},
});
export default controlRenderer;
</script>
Any thoughts on this?