I have implemented a form validation and error display system using TransitionGroup for animations. The issueVisible
flag controls the visibility of the error message, and determineField()
helps determine which field the error pertains to.
The problem is that while errors related to serverError
trigger the animation properly, validation errors on the client don't. Despite resetting issueVisible.value
to false at the beginning of the login()
function, the animation for validation error doesn’t trigger consistently, which means it only appears once, but if I call login()
again, only the timeout
resets, but not the animation. To reset the animation I need to wait until it disappears by itself after 3 sec. Looking for a possible solution.
// 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);
}
};
The issue was solved by adding nextTick()
to the login()
function.