Skip to content

Commit

Permalink
Make form validation less eager
Browse files Browse the repository at this point in the history
  • Loading branch information
petterhj committed Sep 6, 2023
1 parent f5a9d25 commit ab4e6ec
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 40 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ All notable changes to this project will be documented in this file. The format
- Made links clickable in the description of objects, key results and goals.
- It is no longer possible to close open modals or drawers by clicking outside
them. This is meant to prevent accidental data loss in unsaved forms.
- Validation in forms are now less "eager" and errors are only displayed after
attempted form submissions.

## [3.9.0] 2023-09-01

Expand Down
6 changes: 3 additions & 3 deletions src/components/drawers/EditItemDrawer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</template>

<template #page="{ pageIndex, prev }">
<form-section :hide-errors="true">
<form-section>
<template v-if="pageIndex === 1">
<form-component
v-model="thisItem.name"
Expand Down Expand Up @@ -102,7 +102,7 @@
</form-component>
</template>

<template v-if="!thisItem?.archived" #actions="{ handleSubmit }">
<template v-if="!thisItem?.archived" #actions="{ handleSubmit, submitDisabled }">
<pkt-button
v-if="pageIndex === 1"
:text="$t('btn.cancel')"
Expand All @@ -120,7 +120,7 @@

<btn-save
:label="pageIndex === pageCount ? $t('btn.complete') : $t('btn.continue')"
:disabled="loading"
:disabled="submitDisabled || loading"
variant="label-only"
@click="handleSubmit(save)"
/>
Expand Down
6 changes: 3 additions & 3 deletions src/components/drawers/EditKeyResult.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</template>

<template #page="{ pageIndex, prev }">
<form-section :hide-errors="true">
<form-section>
<template v-if="pageIndex === 1">
<form-component
v-model="thisKeyResult.name"
Expand Down Expand Up @@ -79,7 +79,7 @@
</div>
</template>

<template v-if="!keyResult?.archived" #actions="{ handleSubmit }">
<template v-if="!keyResult?.archived" #actions="{ handleSubmit, submitDisabled }">
<pkt-button
v-if="pageIndex === 1"
:text="$t('btn.cancel')"
Expand All @@ -97,7 +97,7 @@

<btn-save
:label="pageIndex === pageCount ? $t('btn.complete') : $t('btn.continue')"
:disabled="loading"
:disabled="submitDisabled || loading"
variant="label-only"
@click="handleSubmit(save)"
/>
Expand Down
6 changes: 3 additions & 3 deletions src/components/drawers/EditObjective.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</template>

<template #page>
<form-section :hide-errors="true">
<form-section>
<form-component
v-model="thisObjective.name"
input-type="textarea"
Expand Down Expand Up @@ -52,12 +52,12 @@
{{ formattedPeriod(newestObjective) }}
</pkt-button>

<template v-if="!objective?.archived" #actions="{ handleSubmit }">
<template v-if="!objective?.archived" #actions="{ handleSubmit, submitDisabled }">
<btn-cancel :disabled="loading" @click="close" />
<btn-save
:label="objective ? $t('btn.updateObjective') : $t('btn.createObjective')"
variant="label-only"
:disabled="loading"
:disabled="submitDisabled || loading"
@click="handleSubmit(save)"
/>
</template>
Expand Down
2 changes: 1 addition & 1 deletion src/components/forms/KpiAdminForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
@close="showEditGoalsModal = false"
/>

<form-section>
<form-section error-summary>
<form-component
v-model="localKpi.name"
input-type="input"
Expand Down
4 changes: 2 additions & 2 deletions src/components/generic/form/FormSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<slot />

<pkt-alert
v-if="validated && !valid && !hideErrors"
v-if="errorSummary && validated && !valid"
skin="error"
class="form-errors"
:title="$t('general.formErrors')"
Expand Down Expand Up @@ -43,7 +43,7 @@ export default {
},
props: {
hideErrors: {
errorSummary: {
type: Boolean,
required: false,
default: false,
Expand Down
42 changes: 42 additions & 0 deletions src/config/validation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { extend, configure, setInteractionMode } from 'vee-validate';
import {
email,
max,
min,
min_value as minValue,
numeric,
required,
} from 'vee-validate/dist/rules';
import i18n from '@/locale/i18n';

export default function configureFormValidation() {
// Set custom interaction mode for VeeValidate - a combination of 'passive' and
// 'eager' (default: 'aggressive').
// https://vee-validate.logaretm.com/v3/guide/interaction-and-ux.html#interaction-modes
// https://github.com/logaretm/vee-validate/blob/v3/src/modes.ts
setInteractionMode('custom', ({ errors }) => {
return {
on: errors.length ? ['input', 'change'] : [],
};
});

// https://vee-validate.logaretm.com/v3/configuration.html#configuration
// https://vee-validate.logaretm.com/v3/guide/localization.html#using-other-i18n-libraries
configure({
defaultMessage: (field, values) => {
values._field_ = i18n.t(`fields.${field}`);

return i18n.t(`validation.${values._rule_}`, values);
},
});

// https://vee-validate.logaretm.com/v3/api/extend.html#extend
extend('required', required);
extend('email', email);
extend('numeric', numeric);
extend('min', min);
extend('min_value', minValue);
extend('max', max);
extend('decimal', (num) => typeof num === 'number');
extend('positiveNotZero', (num) => typeof num === 'number' && num > 0);
}
33 changes: 5 additions & 28 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,7 @@ import Toasted from 'vue-toasted';
import VTooltip from 'v-tooltip';
import VueMeta from 'vue-meta';
import VueFlatPickr from 'vue-flatpickr-component';
import { ValidationProvider, ValidationObserver, extend, configure } from 'vee-validate';
import {
email,
max,
min,
min_value as minValue,
numeric,
required,
} from 'vee-validate/dist/rules';

import { ValidationProvider, ValidationObserver } from 'vee-validate';
import { firestorePlugin } from 'vuefire';

import { PktIcon } from '@oslokommune/punkt-vue2';
Expand All @@ -27,6 +18,7 @@ import PageLayout from '@/components/layout/PageLayout.vue';
import FormComponent from '@/components/FormComponent.vue';

import { auth } from './config/firebaseConfig';
import configureFormValidation from './config/validation';

// import plugin styles
import 'flatpickr/dist/flatpickr.css';
Expand Down Expand Up @@ -66,24 +58,9 @@ Vue.component('FormComponent', FormComponent);
Vue.component('VSpinner', Spinner);
Vue.component('PktIcon', PktIcon);

/* eslint-disable */
configure({
defaultMessage: (field, values) => {
values._field_ = i18n.t(`fields.${field}`);

return i18n.t(`validation.${values._rule_}`, values);
},
});
/* eslint-enable */

extend('required', required);
extend('email', email);
extend('numeric', numeric);
extend('min', min);
extend('min_value', minValue);
extend('max', max);
extend('decimal', (num) => typeof num === 'number');
extend('positiveNotZero', (num) => typeof num === 'number' && num > 0);
// Configure VeeValidate for form validation.
// https://vee-validate.logaretm.com/v3/
configureFormValidation();

Vue.config.productionTip = false;

Expand Down

0 comments on commit ab4e6ec

Please sign in to comment.