Skip to Content
TutorialFeature ModulesForm DraftsReal-time Draft Saving for Forms

Real-time Draft Saving for Forms

Demo Project

https://editor.momen.app/tool/QP7kZReRLgM/WEB?code=O66W2KjDbfKyB&ref=0562398

Introduction

  • Goal: Build a form system that prevents data loss by saving user inputs in real time, eliminating the need for manual save actions.
  • Use Cases: Long-text editing, multi-step government applications, online examinations, and any scenario where users are at high risk of losing data due to accidental page closure or network interruptions.
  • Core Logic: When users click “Create”, the system checks for an existing blank draft. If none exists, it inserts a new record; if one exists, it reuses that ID. When input fields lose focus (On blur), the system automatically updates the record and changes its status from Blank Draft to Filled Draft. A dedicated list panel displays all historical drafts for easy recovery.

Steps

This tutorial uses pre-styled layout blocks from the “Common UI Presets” template page. These preset elements provide basic styling and layout only; they contain no conditional logic, data bindings, or Actionflows. You can copy them directly to skip manual styling and focus on the core logic.

Data Model

To implement the draft system, create a table in the database to store user progress and track status.

Table Name: form

Navigate to the Data tab in the Top Navigation Bar to configure this table.

Field NameTypeNote
idBigintAuto-generated, unique identifier
statusTextEnumerated values: Blank Draft, Filled Draft, Submitted, Deleted
field_1TextBusiness input field 1
field_2BigintBusiness input field 2
account_idBigintForeign key referencing id in the account table

Relationship Mapping: The account table and form table have a One-to-Many relationship (one account owns multiple form/draft records).

Status Flow:The status field governs the entire lifecycle of a record:

  • Blank Draft: A placeholder created when the user opens the modal for the first time.
  • Filled Draft: The user has filled in at least one field and the draft has been auto-saved.
  • Submitted: The form has been officially submitted. It no longer appears in the draft list.
  • Deleted: The draft has been soft-deleted. It no longer appears in the draft list.

Page-Level Data Source

Configure a data source at the Page Form Drafts level to check in real time whether a blank draft already exists for the current logged-in user.

  1. Open the Data panel on the left sidebar and click + next to Data Sources.
  2. Set Name to source_form_empty_draft.
  3. Target Table: Select form.
  4. Request Type: Query.
  5. Limit: 1.
  6. Query Criteria (combined with And):
    • account_id Equal to Logged in user/id
    • status Equal to "Blank Draft"

Reusing Blank Drafts:This logic ensures that each logged-in user has at most one Blank Draft record at any given time. When the user clicks Create again, the system simply reuses the existing blank record instead of generating useless empty entries.

Create Button Actionflow

Select Button Create on the main page and configure its OnClick event. This actionflow handles login validation and blank draft deduplication.

  1. Login Check: Add a Condition node.

    • Name the branch Case: Guest.
    • Condition: getIsLoggedIn is false.
    • Action: Add a Show toast node with the message Please log in first.
  2. Blank Draft Check: Under the Case: Logged In branch, add another nested Condition node.

    • Path 1 - No Blank Draft: Set the condition to source_form_empty_draft/id is null.
      • Insert Data: Target table form. Set status to "Blank Draft" and bind account_id to Logged in user/id.
      • Open Custom Modal: Select Modal Fill Form. Bind the input parameter empty_draft_form_id to the id returned by the previous Insert action.
      • Refresh Data Source: Target the page-level data source source_form_empty_draft.
    • Path 2 - Blank Draft Exists: Set the condition to always (default branch).
      • Open Custom Modal: Select Modal Fill Form. Bind the input parameter empty_draft_form_id directly to source_form_empty_draft/id.
      • Refresh Data Source: Target the page-level data source source_form_empty_draft.

The modal needs to receive and store the draft ID passed from the main page.

  1. Input Parameter: Select the root of Modal Fill Form. Go to the Data tab in the right sidebar.

    • Click + next to Input.
    • Set Name to empty_draft_form_id and Type to Bigint.
  2. Local Variable: Still in the Data tab, click + next to Variable.

    • Set Name to form_id and Type to Bigint. (Default value can be left empty.)
  3. On Page Load:

    • Add a Set variable action.
    • Target: form_id.
    • Value: Bind to Input/empty_draft_form_id.

Input Components and Real-time Saving

Configure the two input fields inside the modal. When users finish typing and move away (blur event), the data is saved automatically.

  1. Input Field 1: Select the text input component. Keep Input value type as Text.
  2. Input Field 2: Select the text input component. Switch Input value type to Bigint.

  1. Configure Auto-Save on Blur for Field 1:

    • Select Input Field 1 and add an event under On blur.
    • Add a Condition node.
      • Path 1 - Input is Empty: Set the condition to: Input Field 1/Value Is null AND Input Field 2/Value Is null.
        • Action: Show toast with message Please fill in at least one field.
      • Path 2 - Input Not Empty: Set the condition to always.
        • Update Data: Target table form. Query criteria: id Equal to Variable/Modal Fill Form/form_id.
        • Parameters: Set status to "Filled Draft". Bind field_1 to Input Field 1/Value.
        • On Success Action: Show toast with message Draft saved successfully.
  2. Configure Auto-Save on Blur for Field 2:

    • Select Input Field 2 and add an event under On blur.
    • Add a Condition node with the same empty-value logic as above.
    • Path 1 - Input is Empty: Same toast拦截.
    • Path 2 - Input Not Empty: Update Data with the same query criteria (id equal to form_id). Set status to "Filled Draft" and bind field_2 to Input Field 2/Value. Show toast Draft saved successfully.

⚠️

Dual-field Empty Intercept:Both input fields must be empty for the interception to trigger. This validation is configured independently on both On blur events, ensuring users cannot bypass the check by only interacting with one field.

Historical Drafts Panel

Create a panel that displays all saved drafts (status = "Filled Draft") belonging to the current user.

  1. Draft Counter:
    • Select the Text: Current number of drafts component.
    • Bind its Content to Logged in user/form/Count.
    • Add a local filter: status Equal to "Filled Draft".

Logged in user/form/Count updates when user data loads or refreshes. The draft list uses Subscription (see below), so we add a Refresh current user data action inside the list’s On subscription success event to keep the counter accurate.

  1. Draft List Data Source:
    • Select the List component inside the modal.
    • Set Request type to Subscription.
    • Target Table: form.
    • Query Criteria (combined with And):
      • account_id Equal to Logged in user/id.
      • status Equal to "Filled Draft".
    • On subscription success: Add a Refresh current user data action to keep the draft counter accurate.

  1. Expand/Collapse State Control:
    • Select the Conditional View Drafts container. It contains two cases: Case Closed and Case Extended.
    • Expand: Inside Case Closed, select Button Drafts. Under its OnClick, add:
      • Switch conditional view → Target Conditional View Drafts, switch to Case Extended.
      • Switch conditional view → Target the secondary conditional view (the one wrapping the list), switch to Case Extended.
    • Collapse: Inside Case Extended, select Button Drafts. Under its OnClick, add:
      • Switch conditional view → Target Conditional View Drafts, switch to Case Closed.
      • Switch conditional view → Target the secondary conditional view, switch to Case Closed.

Synced Conditional Views:This setup uses two conditional view components that must be switched simultaneously. The first controls the button state (Closed/Extended), and the second controls the visibility of the draft list. Using two Switch conditional view actions in the same event ensures they stay in sync.

  1. Load Draft (Apply):
    • Inside the list row, select Text Apply.
    • Under its OnClick, add these actions in order:
      • Set variable: Target form_id. Set value to Data source/List/Current item/id.
      • Set input value: Target Input Field 1. Set value to Data source/List/Current item/field_1.
      • Set input value: Target Input Field 2. Set value to Data source/List/Current item/field_2.

  1. Delete Draft (with Editing Lock):
    • Inside the list row, select Text Delete.
    • Under its OnClick, add a Condition node.
      • Path 1 - Editing Protection: Set condition to Variable/Modal Fill Form/form_id Equal to Data source/List/Current item/id.
        • Action: Show toast with message Cannot delete a draft that is being edited.
      • Path 2 - Safe to Delete: Set condition to always.
        • Update Data: Target table form. Query criteria: id Equal to Data source/List/Current item/id.
        • Parameters: Set status to "Deleted".
        • On Success Action: Show toast with message Draft deleted successfully.

Form Submission

Configure the final submission and exit actions.

  1. Apply Button (Submit):

    • Select Button Apply inside the modal.
    • Under its OnClick, add an Update Data action.
    • Target Table: form.
    • Query Criteria: id Equal to Variable/Modal Fill Form/form_id.
    • Parameters: Set status to "Submitted".
    • Success Actions:
      • Show toast: Submission successful.
      • Close modal: Mode CLOSE_ON_TOP.
  2. Cancel Button (Exit):

    • Select Button Cancel.
    • Under its OnClick, add a Close modal action with Mode CLOSE_ON_TOP.

Verification

Step 1: Verify Blank Draft Reuse Logic

  1. Use the Login Simulation toolkit at the bottom bar to select a test account.
  2. Click the Create button to open the form modal.
  3. Leave both input fields completely empty and click Cancel.
  4. Click Create again.
  5. Expected Result: The system does not create a new record. The Current form ID displayed at the top of the modal is identical to the previous one, confirming the data source successfully executed the reuse logic.

Step 2: Verify Auto-Save on Blur

  1. Inside the modal, type some text into Input Field 1.
  2. Click any blank area outside the input to trigger the blur event.
  3. Expected Result: A toast appears: Draft saved successfully. In the database, the record’s status changes from Blank Draft to Filled Draft.
  4. Clear Input Field 1 so both fields are completely empty, then click outside to trigger blur.
  5. Expected Result: An intercepting toast appears: Please fill in at least one field., and the data is not saved.

Step 3: Verify Draft Recovery and Editing Lock

  1. Expand the draft panel and select any historical draft from the list, then click Apply.
  2. Expected Result: The values in both input fields refresh to match the historical record. The internal form_id variable updates to the selected record’s ID.
  3. In the draft list, click Delete next to the draft currently being edited.
  4. Expected Result: The system triggers the editing lock protection and shows: Cannot delete a draft that is being edited.

Step 4: Verify Submission Status Change

  1. Click Apply (Submit) inside the modal.
  2. Expected Result: A toast appears: Submission successful. The modal closes. The submitted record no longer appears in the draft list. In the database, the record’s status is now Submitted.

Step 5: Verify Deletion Status Change

  1. Click Create to open a new form modal. Fill in at least one field and let it auto-save to create a new Filled Draft.
  2. In the draft list, click Delete on this new draft (make sure it is not currently loaded in the editor).
  3. Expected Result: A toast appears: Draft deleted successfully. The record disappears from the list. In the database, the record’s status is now Deleted.
Last updated on