BluKavantUI Design system
OUTSYSTEMS

Save, reload & attachments

Build data-driven forms in OutSystems with one shared screen and reusable storage.

OUTSYSTEMS · PUBLISHED EXAMPLE

One RawJson field. One shared screen. One upload endpoint.

Save the whole form definition, then reconstruct it from the same JSON. Pages, sections, field settings and conditions travel with the definition. New forms are records loaded by FormId on the same screen.

  1. Design and save: FormBuilder → DefinitionJson → RawJson.
  2. Load and fill: RawJson → FormRenderer → ValuesJson.
  3. Attach files: shared upload endpoint → stored file ID → ValuesJson.

The published BluGrid_Sample.FormBuilderDemo saves definitions, answers and real attachment bytes in OutSystems. A full page reload restored the saved response; the downloaded attachment matched the original byte for byte.

Native demo access requires an existing BluGridDemoEditor role assignment. This guide describes the OutSystems setup; the website’s interactive examples save locally in the browser.

1. Keep forms as data

The demo uses one private BluFormDemoStore Entity. Its Kind attribute distinguishes three row types; the same RawJson Text attribute stores complete definitions and responses in separate rows.

KindStored contentAssociated data
DefinitionRawJson = complete DefinitionJsonOwnerUserId, FormKey, Revision
ResponseRawJson = complete ValuesJsonOwnerUserId, FormKey, definition Revision
AttachmentBinaryContent = actual file bytesOwner, FormKey, FieldKey, ClientKey, name, MIME type and size

Configure RawJson with enough capacity for the complete document and reject truncation. File bytes stay outside JSON; answers contain durable file references. The demo keeps the latest response per editor and FormId. Add a ResponseId as data when your application needs multiple responses.

Reuse the same screen, Entity and integration for each new form. Shared platform objects still count under your OutSystems licence.

2. Load, save and reload on the same screen

Reference FormBuilder, FormRenderer and Form_PrepareSubmission from BluKavantUi_Forms. Switch between authoring and filling within one screen.

Load the form and bind the Blocks

Use FormId as a screen input. Authorize it on the server, derive the owner from GetUserId(), and load its Definition and Response rows. Keep the Blocks behind a readiness If until the load completes.

OutSystems Block bindings
FormBuilder.FormId        = FormId
FormBuilder.DefinitionJson = DefinitionJson
FormRenderer.FormId       = FormId
FormRenderer.DefinitionJson = DefinitionJson
FormRenderer.ValuesJson   = ValuesJson
FormRenderer.ResetKey     = ResetKey

Assign the definition row’s RawJson to DefinitionJson and the response row’s RawJson to ValuesJson. Change ResetKey on an explicit reload or record switch, not on every edit. OnDefinitionChanged and OnValuesChanged update the corresponding screen variables.

Save the complete definition
  1. Map OnSaveRequested’s RequestId, FormId and DefinitionJson to handler inputs RequestedRequestId, RequestedFormId and RequestedDefinitionJson.
  2. Call a shared Server Action. Check edit permission and expected revision, then persist RequestedDefinitionJson in the Definition row’s RawJson.
  3. Only after successful persistence, set SaveResultRequestId to RequestedRequestId, SaveResultSuccess to True and SaveResultMessage to the confirmation.
  4. On failure, acknowledge the same request with False and a useful message. The draft remains available for retry.
Save answers and restore them later
  1. OnSubmitRequested supplies RequestId, FormId and ValuesJson. Call Form_PrepareSubmission with the loaded definition and requested values.
  2. If valid, call your shared Server Action. Independently validate the answers against the stored definition and verify attachment ownership, then save the complete ValuesJson in a Response row’s RawJson.
  3. Return the matching SubmitResultRequestId, SubmitResultSuccess and SubmitResultMessage only after the operation completes.
  4. Reload the saved definition and answers by FormId; update ResetKey. Saved attachment names return without uploading the files again.

Keep the definition revision with the response. The demo retains older answers in storage but does not apply them to a different definition revision. Form_PrepareSubmission also supplies PayloadJson and ResponseText for your application’s integrations; it does not send email.

How the published demo implements it

The private FormDemo_Store Server Action accepts Load, SaveDefinition and SaveResponse. Its LoadOrSave branch sends Load to a separate LoadDocument query; StoreDocument handles saves. Keep load queries separate from save-time JSON validation. The demo targets SQL Server and allowlists service_request and event_feedback. Your application can resolve its own authorized form-record IDs through the same screen.

3. Connect one shared upload endpoint

Add a File upload field in the builder. FormRenderer provides drag and drop, Browse, progress, retry and cancel. Configure the upload connection once on the screen; every form and file field reuses it.

Published native demo bindings
UploadUrl = "/BluGrid_Sample/rest/BluFormDemoFiles/upload"
UploadFormat = "Binary"
UploadHeadersJson = UploadHeadersJson
Binary request and stored response

In the current native library, UploadFormat = Binary sends the raw file as the request body with Content-Type application/octet-stream. The URL carries formId, fieldKey, clientKey, fileName and fileType. Define the exposed REST method’s body input as Binary Data. UploadFormat defaults to Multipart for existing consumers.

The endpoint authorizes access, validates the saved field’s limits and file content, and stores the bytes before returning a successful JSON response:

Upload response JSON
{"Id":"123","Name":"evidence.pdf","Size":12840,"Type":"application/pdf"}

ValuesJson then contains the reference under the field key:

Saved answer JSON
{"evidence":[{"Id":"123","Name":"evidence.pdf","Size":12840,"Type":"application/pdf"}]}

For the default Multipart transport, the POST fields are file, formId, fieldKey and clientKey. Let the browser set its multipart Content-Type.

Authorization and downloads

The demo’s authorized Load issues a 45-minute owner/form-scoped token. Pass it as the X-Blu-Upload-Token header through UploadHeadersJson. Both upload and download validate that capability and recheck the owner’s editor role. Do not store the token in definition/answer JSON or place it in a URL.

The same BluFormDemoFiles API exposes GET /download with formId and fileId. The demo’s saved-attachment selector fetches the bytes with the authorization header and downloads the original filename. Your application must validate every submitted file ID against its owner, form and field.

Limits and lifecycle

The demo accepts nonempty TXT, PDF, PNG and JPEG files up to 5 MB, subject to stricter field limits. It retains up to 100 files / 50 MB per editor and 20 uploads per field. A pending or failed upload blocks Next/Submit until completed or removed. Removing an attachment reference does not delete stored bytes; your application owns retention, deletion and malware scanning. Repeating a clientKey returns the existing file only when its bytes and metadata match.

4. Test the complete round trip

  1. Open the native demo, select Workplace service request, edit a label and save.
  2. Choose Fill a form, complete its steps and attach a small supported test file. Wait for Uploaded, then submit.
  3. Reload the page and choose Fill a form again. Confirm the definition, answers and attachment return.
  4. Use Download saved attachment and compare it with the original. Switch to the second form and back.
  5. Try Simulate rejected save / submit to confirm failed operations preserve the draft.

Reset playground reloads stored data; it does not delete it. Refreshing or switching forms does not persist unsaved edits automatically.

Search BluKavantUI