diff --git a/frontend/src/components/form/ValidationForm.vue b/frontend/src/components/form/ValidationForm.vue index e5cc4f8..67d89f9 100644 --- a/frontend/src/components/form/ValidationForm.vue +++ b/frontend/src/components/form/ValidationForm.vue @@ -31,8 +31,20 @@ function onSubmit() { const valid = validate(); if (valid) { emit("submit"); + } else { + for (const component of validationComponents.value) { + if ( + component.isMounted && + component.exposed?.validate && + component.exposed?.focus + ) { + if (!component.exposed.validate()) { + component.exposed.focus(); + return; + } + } + } } - // TODO: Else scroll to first error and focus input. } diff --git a/frontend/src/components/form/ValidationFormInput.vue b/frontend/src/components/form/ValidationFormInput.vue index 3fcb18e..b772d3e 100644 --- a/frontend/src/components/form/ValidationFormInput.vue +++ b/frontend/src/components/form/ValidationFormInput.vue @@ -30,6 +30,7 @@ const displayLabel = computed(() => : undefined ); +const label = ref(); const input = ref(); const valid = ref(true); const validated = ref(false); @@ -72,13 +73,6 @@ function onInput() { }); } -function reset() { - withInputElement((element) => { - element.value = ""; - onInput(); - }); -} - function validate(): boolean { const element = input.value; if (!element) { @@ -90,7 +84,20 @@ function validate(): boolean { return valid.value; } +function reset() { + withInputElement((element) => { + element.value = ""; + onInput(); + }); +} + +function focus() { + label.value?.scrollIntoView(); + input.value?.focus(); +} + defineExpose({ + focus, validate, }); @@ -101,7 +108,7 @@ onMounted(() => {