diff --git a/packages/ui-solid/fixtures/xforms/validation/1-validation.xml b/packages/ui-solid/fixtures/xforms/validation/1-validation.xml new file mode 100644 index 000000000..4d8022c6d --- /dev/null +++ b/packages/ui-solid/fixtures/xforms/validation/1-validation.xml @@ -0,0 +1,93 @@ + + + + Validation Form + + + + + Please enter your profession + + + It has to be two + + + + + اپنا پروفیشن بتائیں + + + صرف دو ہی ہوسکتی ہیں + + + + + + + + + + + + + + + + + + + + pk + + + + ca + + + + us + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/web-forms/src/components/FormHeader.vue b/packages/web-forms/src/components/FormHeader.vue index 74b4cc3d6..d6d04d171 100644 --- a/packages/web-forms/src/components/FormHeader.vue +++ b/packages/web-forms/src/components/FormHeader.vue @@ -3,7 +3,8 @@ import { type FormLanguage, type RootNode, type SyntheticDefaultLanguage } from import PrimeButton from 'primevue/button'; import PrimeCard from 'primevue/card'; import PrimeMenu from 'primevue/menu'; -import { ref } from 'vue'; +import PrimeMessage from 'primevue/message'; +import { computed, ref } from 'vue'; import FormLanguageDialog from './FormLanguageDialog.vue'; import FormLanguageMenu from './FormLanguageMenu.vue'; @@ -19,6 +20,14 @@ const languages = props.form.languages.filter(isFormLanguage); const print = () => window.print(); +const formErrorMessage = computed(() => { + const violationLength = props.form.validationState.violations.length; + + if(violationLength === 0) return ''; + else if(violationLength === 1) return '1 question with error'; + else return `${violationLength} questions with errors`; +}); + const items = ref([ { label: 'Print', @@ -38,34 +47,22 @@ if(languages.length > 0){ const handleLanguageChange = (event: FormLanguage) => { props.form.setLanguage(event); }; + +const scrollToFirstInvalidQuestion = () => { + document.getElementById(props.form.validationState.violations[0].nodeId + '_container')?.scrollIntoView({ + behavior: 'smooth' + }); +} @@ -124,22 +152,64 @@ const handleLanguageChange = (event: FormLanguage) => { } } -.smaller-screens { - background-color: var(--surface-0); - filter: drop-shadow(0px 2px 6px rgba(0, 0, 0, 0.15)) drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.30)) ; +.form-error-message.p-message.p-message-error { + border-radius: 10px; + background-color: var(--error-bg-color); + border: 1px solid var(--error-text-color); + width: 70%; + margin: 0rem auto 1rem auto; + position: sticky; + top: 0; + // Some PrimeVue components use z-index. + // Default value for those are either 1000 or 1100 + // So 5000 here is safe. + z-index: 5000; + display: none; + + :deep(.p-message-wrapper) { + padding: 0.75rem 0.75rem; + flex-grow: 1; + } - h1 { - padding-left: 10px; - font-size: 1.5rem; + :deep(.p-message-text){ + font-weight: 400; + flex-grow: 1; + + .fix-errors { + float: right; + cursor: pointer; + } } - .form-options{ - padding-right: 10px; +} + +.smaller-screens { + .title-bar{ + background-color: var(--surface-0); + filter: drop-shadow(0px 2px 6px rgba(0, 0, 0, 0.15)) drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.30)) ; + + h1 { + padding-left: 10px; + font-size: 1.5rem; + } + + .form-options{ + padding-right: 10px; + } + + .btn-menu{ + color: var(--surface-900); + } } - - .btn-menu{ - color: var(--surface-900); + + .form-error-message.p-message.p-message-error { + margin-top: 1rem; + margin-bottom: 0; } } +:global(.submit-pressed .form-error-message.p-message.p-message-error ){ + display: block; +} + diff --git a/packages/web-forms/src/components/FormQuestion.vue b/packages/web-forms/src/components/FormQuestion.vue index ff38b2744..e2e6e6d27 100644 --- a/packages/web-forms/src/components/FormQuestion.vue +++ b/packages/web-forms/src/components/FormQuestion.vue @@ -13,11 +13,52 @@ const isSelectNode = (n: AnyLeafNode) : n is SelectNode => n.nodeType === 'selec + + \ No newline at end of file diff --git a/packages/web-forms/src/components/OdkWebForm.vue b/packages/web-forms/src/components/OdkWebForm.vue index 598ce339b..526ee353b 100644 --- a/packages/web-forms/src/components/OdkWebForm.vue +++ b/packages/web-forms/src/components/OdkWebForm.vue @@ -11,6 +11,8 @@ const props = defineProps<{ formXml: string }>(); const odkForm = ref(); +const submitPressed = ref(false); + const emit = defineEmits(['submit']); initializeForm(props.formXml, { @@ -22,19 +24,26 @@ initializeForm(props.formXml, { }).catch(() => {}); // eslint-disable-line -- noop const handleSubmit = () => { - emit('submit'); + if(odkForm.value?.validationState.violations?.length === 0){ + emit('submit'); + } + else{ + submitPressed.value = true; + window.scrollTo({top: 0, behavior: 'smooth'}); + } } +