Skip to content

Commit

Permalink
🐛 [open-formulieren/open-forms#3511] Fix flickering inputs on Webkit …
Browse files Browse the repository at this point in the history
…browsers

Some difference in the JS engine in WebKit (the browser engine behind
Safari or any other browser on iOS/MacOS) vs. Gecko (Firefox) and Blink
(Chromium, Edge) seems to cause a different (debounce) behaviour and
or event firing/acting on events w/r to the Formio renderer.

On Webkit, the formio initialized event triggered with mismatching
backend data, causing the form field inputs to be cleared and the
submission to be updated, which in turn triggers the logic check again
due to a change event being fired. This then leads again to a change
in the formio configuration and the formio renderer re-initializing,
ad infinitum. Somewhere the form data and form configuration state
goes out of sync and it's incredibly hard to manage this, especially
due to the large number of related issues in the past.

Since we use the formio initialized event pretty much only to form
step data from earlier submissions or when navigating between steps,
we avoid setting updated form data at all in formio initialized events
triggered by logic evaluations. The logic evaluation itself already
manages the form instance submission data, in case that the backend
returns calculated/derived values, for example.

I truly hope this doesn't break anything else, but due to the lack
of tests (granted, it's near impossible to test this mess) and
complexity of this part of the code base, I can't say I'm very
confident in this fix.

Backport-of: #559
  • Loading branch information
sergei-maertens committed Sep 29, 2023
1 parent a66e1b9 commit 9b68e06
Showing 1 changed file with 17 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/components/FormStep/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ class AbortedLogicCheck extends Error {
const initialState = {
configuration: null,
backendData: {},
formioInitialized: false,
canSubmit: false,
logicChecking: false,
isFormSaveModalOpen: false,
Expand Down Expand Up @@ -212,6 +213,7 @@ const reducer = (draft, action) => {
} = action.payload;
draft.configuration = configuration;
draft.backendData = data;
draft.formioInitialized = false;
draft.canSubmit = canSubmit;
draft.logicChecking = false;
draft.isNavigating = false;
Expand All @@ -223,6 +225,11 @@ const reducer = (draft, action) => {
break;
}

case 'FORMIO_INITIALIZED': {
draft.formioInitialized = true;
break;
}

case 'BLOCK_SUBMISSION': {
const {logicChecking = false} = action.payload || {};
draft.canSubmit = false;
Expand Down Expand Up @@ -305,6 +312,7 @@ const FormStep = ({
{
configuration,
backendData,
formioInitialized,
canSubmit,
logicChecking,
isFormSaveModalOpen,
Expand Down Expand Up @@ -708,6 +716,14 @@ const FormStep = ({
return;
}

// formio initialized also fires when the formio configuration changes bceause of
// logic, but we only tap into this hook to set the backend-loaded submission data.
// Once this is done, we don't want to run anything anymore.
// Otherwise this causes problems wich change events triggering and "bouncing" back
// and forth (in WebKit browsers) with the logic check via the onFormIOChange, see
// open-formulieren/open-forms#3511.
if (formioInitialized) return;

// We cannot filter 'blank' values to prevent Formio validation from running, as
// Formio will use the default values in that case which have been explicitly
// unset. In the situation that we have invalid backend data (loading a submission
Expand All @@ -722,6 +738,7 @@ const FormStep = ({
// for FormIO (multivalue input is one example why that's needed).
formInstance.setSubmission({data: cloneDeep(backendData)}, {noValidate: true});
}
dispatch({type: 'FORMIO_INITIALIZED'});
};

/**
Expand Down

0 comments on commit 9b68e06

Please sign in to comment.