Incorporated a form validation and error display system utilizing TransitionGroup for animations. The flag issueVisible
manages the visibility of the error message, while determineField()
aids in identifying the field related to the error.
The issue arises when validation errors on the client fail to trigger the animation consistently, unlike errors associated with serverError
which do trigger the animation correctly. Despite setting issueVisible.value
to false at the start of the login()
function, the animation for validation error tends to show only once, and subsequent calls to login()
reset the timeout but not the animation. To reset the animation, one must wait for it to disappear naturally after 3 seconds. Seeking a viable solution to this problem.
// template
<TransitionGroup name="bounce">
<template v-if="issueVisible">
<ItemFormError
class="modal__error"
:fieldName="determineField()"
:issues="issues">
<template #icon>
<IconError class="modal__error-icon" />
</template>
</ItemFormError>
</template>
</TransitionGroup>
// script
const issues = ref<
FlatErrors<typeof LoginSchema>['nested'] & { server?: string }
>({});
const issueVisible = ref(false);
const determineField = () => {
if (issues.value.username) return 'username';
if (issues.value.password) return 'password';
if (issues.value.server) return 'server';
return '';
};
let timeout: number | undefined;
const login = async () => {
const result = safeParse(LoginSchema, loginData, {
abortPipeEarly: true,
});
issueVisible.value = false;
if (timeout) {
clearTimeout(timeout);
}
if (result.success) {
issues.value = {};
issueVisible.value = false;
try {
await storeAuth.login(loginData);
if (storeAuth.serverError) {
issues.value.server = storeAuth.serverError;
} else {
setTimeout(() => {
router.push({ name: 'home' });
}, 3000);
}
} catch (err) {
issues.value.server = storeAuth.serverError;
issueVisible.value = true;
timeout = setTimeout(() => {
issueVisible.value = false;
}, 3000);
}
} else {
issues.value = flatten<typeof LoginSchema>(result.issues).nested;
issueVisible.value = true;
timeout = setTimeout(() => {
issueVisible.value = false;
}, 3000);
}
};