Pro Forms – Rich Text (WordPress/TinyMCE style) content is wiped when a Repeater row is added or removed

Environment

  • Bricksforge 4.0.0-beta.2 (also reproducible on 3.1.8.9)
  • Bricks 2.4-rc / 2.3.12
  • WordPress 7.1, PHP 8.4
  • Rich Text field with “Style: WordPress” (TinyMCE), multi-step form

What happens
In a Pro Form containing both a Rich Text field (WordPress style) and a Repeater,
the Rich Text content is silently discarded if the user adds or removes a repeater
row after typing the text. The hidden transport input is emptied, so the field
arrives empty in $_POST and in the custom action. The editor itself still shows
the text, which makes the data loss easy to miss.

Steps to reproduce

  1. Build a multi-step Pro Form with a Rich Text field (Style: WordPress) and a Repeater.
  2. Type some text into the Rich Text field.
  3. Go to the repeater and click the “+” (or “-”) button to add/remove a row.
  4. Submit the form.
  5. The Rich Text value is empty. Console check before submitting:
    document.querySelectorAll(‘input[data-type=“rich-text”]’).forEach(i => console.log(i.name, i.value))
    → empty string.
    Typing into the editor again after step 3 restores the value, which is why the
    issue looks intermittent.

Cause (bricksforge_elements.js)
handleRichText() copies the textarea value into the hidden input:

handleRichText(){
this.form.querySelectorAll(“.brf-rich-text-container”).forEach(e => {
let t = e.closest(“.form-group”).querySelector(“input[type=‘hidden’][data-type=‘rich-text’]”);
t && (t.value = e.value);
})
}

In WordPress/TinyMCE mode, “.brf-rich-text-container” is the textarea that TinyMCE
hides on init. TinyMCE only writes back to that textarea on editor.save() or on a
real form submit; neither happens here, because Bricksforge submits via AJAX and
never calls triggerSave()/save(). The textarea therefore stays permanently empty,
and handleRichText() overwrites the correctly populated hidden input with “”.

handleRichText() is called from updateRepeaterItemIndexes(), which runs on init
(harmless, everything is still empty) and on addRepeaterField() /
removeRepeaterField() — hence the exact trigger.

Note on Quill mode: there “.brf-rich-text-container” is a

, so e.value is
undefined. handleRichText() currently matches neither of the two modes.

Suggested fix
Before reading the textarea in handleRichText(), sync the editor:

if (window.tinymce) {
const ed = window.tinymce.get(e.id);
if (ed) ed.save();
}

and skip / handle the Quill case separately (read .ql-editor innerHTML, or leave
the hidden input untouched, since Quill already keeps it in sync via text-change).

Current workaround
A small frontend script that hooks every TinyMCE instance inside .brf-field-rich-text
and calls editor.save() on input/change/keyup/blur/ExecCommand/SetContent, which keeps
the textarea current so Bricksforge’s own copy logic reads the right value.

Hi Ocram,

thanks for the outstanding report - your analysis is spot on, I confirmed every step in the code.

Here is what we will do: before reading the textarea, the fix syncs the TinyMCE instance via editor.save() so the textarea is current, and the copy is skipped for Quill fields, which already keep their hidden input up to date on their own.

Your editor.save() workaround is exactly the right idea and safe to keep in place until the fix ships.

Best,
Daniele