Hi,
i have the following problem, i want to use the validation feature but everytime i use handleChange(path, data), it doesnt do anything for me. setting control.data = newdata directly changes control.data, but doesnt trigger the validation.
Im using vue3.
RouteHandler contains the JsonForms
<script setup lang="ts">
import TableView from '../views/TableView.vue';
import HeadlineWithBreadcrumps from '../components/HeadlineWithBreadcrumps/HeadlineWithBreadcrumps.vue';
import { computed, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useMainStore } from '../store';
import { JsonForms, JsonFormsChangeEvent, useJsonFormsControl } from "@jsonforms/vue";
import { getDataViewActionByRel } from '../helpers';
import { storeToRefs } from 'pinia';
import { markRaw } from 'vue';
// TODO switch with capeable Renderes from old project
import RendererList from '../renderers'
import { vanillaRenderers } from "@jsonforms/vue-vanilla";
import { useActionStore } from '../store/ActionStore/ActionStore';
import { useRerenderStore } from '../store/RerenderStore';
import { useRowStore } from '../store/RowStore';
const reRenderStore = useRerenderStore();
const rerenderKey = computed(() => reRenderStore.rerenderKey);
const route = useRoute();
const DataView = ref<any>();
const JSONFormData = ref('');
const store = useMainStore();
const { activeAction, isLoggedIn } = storeToRefs(store);
const schema = computed(() => {
if (activeAction.value && Object.keys(activeAction.value).length) {
const index = useActionStore()._activeAction.steps.findIndex((step: { id: any; }) => step.id === useActionStore()._activeStep.id);
if (activeAction.value.steps[index]?.dataSchema) {
const { dataSchema } = activeAction.value.steps[index];
if (typeof dataSchema === 'string') {
return JSON.parse(dataSchema);
}
return dataSchema || {};
} else {
console.log("Active Step has no Data Scheme");
}
}
return {};
});
const uiSchema = computed(() => {
if (activeAction.value && Object.keys(activeAction.value).length) {
const index = useActionStore()._activeAction.steps.findIndex((step: { id: any; }) => step.id === useActionStore()._activeStep.id);
if (activeAction.value?.steps[index]?.uiSchema) {
const { uiSchema } = activeAction.value.steps[index];
if (typeof uiSchema === 'string') {
return JSON.parse(uiSchema);
}
return uiSchema || {};
} else {
console.log("Active Step has no UI Scheme");
}
}
return {};
});
const renderers = [
...Object.freeze(vanillaRenderers),
...Object.freeze(RendererList)
]
const getDataViewFromStore = async () => {
await store.setDataView();
const { dataview }: any = store.getDataView;
DataView.value = dataview;
}
const determineView = computed(() => {
const formRoutes = ['/login', '/forgot-password', '/reset-password', '/change-password'];
if ((useActionStore()._activeAction)) {
if (useActionStore()._activeStep.type === 'FORM') return JsonForms;
}
// Check if the route is in the formRoutes array
if (formRoutes.includes(route.path)) return JsonForms;
// Default to TableView for other routes
return TableView;
});
getDataViewFromStore();
watch(DataView, () => {
if (route.params.path === 'change-password') return;
console.log("Updating DataView: " + getDataViewActionByRel(DataView.value.actions, route.params.path));
console.log(DataView.value.actions);
console.log(route.params.path);
store.setActiveAction(getDataViewActionByRel(DataView.value.actions, route.params.path));
if (store.activeAction) {
store.setActiveStep(store.activeAction.steps[0]);
}
});
</script>
<template>
<HeadlineWithBreadcrumps v-if="isLoggedIn" />
<component :is="determineView" :key="rerenderKey" :data="useRowStore().getRow" :renderers="markRaw(renderers)" :schema="schema"
:uischema="uiSchema" />
</template>
InputRenderer:
<template>
<div class="input-renderer">
<DefaultInput
:label="control.label"
:value="control.data"
:type="getInputType()"
@add="setFormData"
@input="onInput"
:secondary="getHierarchy()"
:loading="false"
:icon="getIconPath()"
:required="control.required"
:disabled="!control.enabled || appliedOptions.readonly"
:search="true"
:errorMessage="control.errors"
:focus="appliedOptions.focus"
>
</DefaultInput>
{{ control.errors || "Ok" }}
</div>
</template>
and some parts of the code:
const onInput = (event: Event) => {
const target = event.target as HTMLInputElement;
const newvalue = target.value;
console.log(
"Updating control.data with: " + preProcessInput(sanitizeData(newvalue))
);
console.log(control.path);
console.log(preProcessInput(sanitizeData(newvalue)));
jsonformsBindings.handleChange(control.path, preProcessInput(sanitizeData(newvalue)));
console.log(jsonformsBindings.handleChange);
//control.data = preProcessInput(sanitizeData(newvalue));
const isValid = computed(() => ajv.validate(control.schema, control.data));
console.log("Updated control.data: ", control.data);
console.log("Possible Errors: " + control.errors);
return isValid;
};
isValid is always right, so i guess the validation is fine. But i cant get control.errors to update with the data (that doesnt update with any use of handleChange)
and
DefaultInput:
<template>
<div :class="[
'default-input',
'form-group',
{ 'has-validation-feedback': hasValidationFeedback, disabled },
]">
<label v-if="type !== 'hidden'" :for="field">{{ label }}</label>
<div class="input-group">
<input ref="input" :id="field" :type="vType" class="default-input__input" :class="{
'default-input__input--secondary': secondary,
'default-input__input--loading': loading,
'default-input__input--disabled': disabled,
'default-input__input--search': search,
'is-valid': isValid === true,
'is-invalid': isValid === false,
}" :disabled="disabled" v-model="value" @change="$emit('add', value)" @keydown="validateKey" />
<div v-if="type === 'password'" class="input-group-append" @click="forceVisible = !forceVisible">
<font-awesome-icon class="toggle-password-visibility" :icon="forceVisible ? 'eye' : 'eye-slash'" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { v4 } from 'uuid';
import { computed, ref, onMounted, useSlots } from 'vue';
interface InputProps {
label: string,
value: string | number,
type: string,
defaultValue?: string,
validationFeedback?: string,
primary?: boolean,
secondary?: boolean,
loading?: boolean,
icon?: string,
action?: string,
disabled?: boolean,
search?: boolean,
errorMessage?: any,
isValid?: boolean,
focus?: boolean,
};
const props = defineProps<InputProps>();
const slots = useSlots();
const forceVisible = ref(false);
const field = computed(() => `default-input-${v4()}`);
const value = ref(props.value);
const vType = computed(() => (props.type === 'password' ? (forceVisible.value ? 'text' : 'password') : props.type));
const hasValidationFeedback = computed(() => !!slots['validation-feedback'] && props.isValid !== null);
const inputRef = ref<HTMLInputElement | null>(null);
onMounted(() => {
if (props.focus && inputRef.value) {
inputRef.value.focus();
}
});
const emit = (event: string) => {
const eventDetail = new CustomEvent(event);
window.dispatchEvent(eventDetail);
};
const validateKey = (event: KeyboardEvent) => {
emit("form-validate");
if (props.type === 'number') {
const regex = new RegExp(/^[0-9.,]+$/);
if (
event.key !== 'Backspace' &&
event.key !== 'Delete' &&
!((event.ctrlKey || event.metaKey) && event.key === 'a') &&
!regex.test(event.key)
) {
event.preventDefault();
}
}
};
</script>
What am i overlooking?