Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 11 additions & 15 deletions src/plugin/VStepperForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,6 @@ function setPageToError(pageIndex: number, page?: Page, source = 'submit'): void
let debounceTimer: ReturnType<typeof setTimeout>;

function onFieldValidate(field: Field, next: () => void): void {
const errors = $useForm.errorBag as ValidateResult['errors'];
const shouldAutoPage = (field.autoPage || settings.value.autoPage ? next : null) as () => void;

// If autoPage //
Expand All @@ -606,20 +605,17 @@ function onFieldValidate(field: Field, next: () => void): void {
// First validate the page before proceeding to the next page //
$useForm.validate()
.then((res: ValidateResult) => {
if (res.valid) {
// debounce next //
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
checkForPageErrors(errors, 'field', shouldAutoPage);
}, (field?.autoPageDelay ?? settings.value?.autoPageDelay));

return;
}

const page = computedPages.value[currentPageIdx.value];
const pageIndex = computedPages.value.findIndex((p) => p === page);

setPageToError(pageIndex, page, 'validating');
// `validate()` covers the whole form, so fields on later pages
// are still invalid while the user is on an earlier one. Only
// the current page's errors may block auto paging, which is
// what `checkForPageErrors` filters on (same as the next button).
const errors = res.errors as unknown as ValidateResult['errors'];

// debounce next //
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
checkForPageErrors(errors, 'field', shouldAutoPage);
}, (field?.autoPageDelay ?? settings.value?.autoPageDelay));
})
.catch((error: Error) => {
console.error('Error', error);
Expand Down
56 changes: 56 additions & 0 deletions src/plugin/__tests__/VStepperForm.cy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import {
object as yupObject,
string as yupString,
} from 'yup';
import type { Field, Page } from '../../plugin/types';
import * as DATA from '@cypress/templates/testData';
import VStepperForm from '../VStepperForm.vue';
Expand Down Expand Up @@ -637,6 +641,58 @@ describe('Stepper Form', () => {
.should('exist')
.and('be.visible');
});

// ? The validation schema covers the whole form, so fields on later pages
// ? are always invalid while the user is still on an earlier page. Auto
// ? paging must only care about the errors on the current page. //
it('should auto page when a later page still has unfilled required fields', () => {
const schema = yupObject({
address: yupString().required('Address is required'),
animal: yupString().required('Animal is required'),
});

cy.mount(VStepperForm as any, {
props: {
modelValue: { address: null, animal: null },
pages: [
{
fields: [
{
autoPage: true,
label: 'Animal',
name: 'animal',
options: [
{ label: 'Rabbit', value: 'rabbit' },
{ label: 'Duck', value: 'duck' },
],
required: true,
type: 'buttons',
},
],
title: 'Page 1',
},
{
fields: [defaultFields.address],
title: 'Page 2',
},
],
validationSchema: schema,
},
global,
});

cy.getDataCy('vsf-field-address')
.should('not.exist');

cy.getDataCy('vsf-field-animal')
.first()
.click();

// Moved onto the next page //
cy.getDataCy('vsf-field-address')
.should('exist')
.and('be.visible');
});
});

describe('Header Tooltip', () => {
Expand Down
19 changes: 0 additions & 19 deletions src/plugin/composables/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { watchDebounced } from '@vueuse/core';
import type {
UseAutoPage,
UseBuildSettings,
UseColumnErrorCheck,
UseDeepMerge,
Expand Down Expand Up @@ -84,23 +82,6 @@ export const useBuildSettings: UseBuildSettings = (stepperProps: Settings) => {
};


/**
* Automatically pages to the next field.
*/
export const useAutoPage: UseAutoPage = (options) => {
const { emit, field, modelValue, settings } = options;
watchDebounced(modelValue, () => {
if (field?.autoPage == false) {
return;
}

if (field?.autoPage || settings?.autoPage) {
emit('next', field);
}
}, { debounce: (field?.autoPageDelay ?? settings?.autoPageDelay) });
};


/**
* Checks if the column values are between 1 and 12.
*/
Expand Down
13 changes: 0 additions & 13 deletions src/plugin/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,19 +268,6 @@ export interface UseDeepMerge {
): Record<string, any>;
}

export interface UseAutoPage {
(
options: {
emit: {
(e: 'next', field: Field): void;
},
field: Field;
modelValue: any;
settings: Settings;
}
): void;
}

export interface UseColumnErrorCheck {
(
options: {
Expand Down
Loading