dimah-survey
Lifecycle

Response lifecycle

Start from a frozen definition, save drafts, and validate the same snapshot on submit.

startResponse copies publishedJson into response.definition. Every draft write and submit check remains tied to that snapshot—not the current survey draft and not a later publish.

A response is both the answer data and the SurveyJS definition needed to interpret it.

States and transitions

StatusMeaningAllowed next actions
draftAnswers may be incompletePartial save, submit, or abandon
submittedThe stored definition accepted the dataReopen or idempotent resubmit
abandonedClosed without submissionReopen
OperationEffect
startResponseCreate a draft or return the response selected by collection settings
savePartialReplace data on a draft
submitResponseValidate the snapshot and store the accepted data
abandonResponseClose a draft without changing definition or data
reopenResponseMove a submitted or abandoned response back to draft

savePartial and abandonResponse throw RESPONSE_CLOSED unless the row is a draft. reopenResponse throws RESPONSE_CLOSED on a draft, and when settings.reopen is false.

Save a draft

Partial save replaces the entire data object; it is not a key patch.

With the default sanitizePartial: "clear", the server loads the stored definition, assigns the posted data, runs clearIncorrectValues(true), and persists the resulting survey.data. It does not run required-question validation, so an incomplete draft remains valid.

"replace" stores the payload as sent.

Questions with choicesByUrl keep their posted value through the clear. The server does not fetch that URL.

Submit against the snapshot

The default validateResult loads response.definition, removes values that cannot be assigned, runs SurveyJS validate(), and returns the resulting survey.data to persist. An invalid result throws VALIDATION_FAILED with the failing question names in questions.

Replace validateResult for application-specific checks. It still receives the stored definition. Return the object to persist, return nothing to keep the input, or throw an APIError to reject the submit. See Configuration.

A repeated submit of a row that is already submitted returns that row when the cleaned payload matches stored data. Omitting data also returns the stored row. A different payload fails with RESPONSE_CLOSED.

Lifecycle hooks

onStart runs only before a new insert; a resumed response skips both start hooks. onSubmit runs after validation and before the submitted write. Throwing from either on* callback aborts the write.

afterStart and afterSubmit run after the row has been stored. A failure there leaves the write in place. An idempotent resubmit does not run submit hooks again.

Handle concurrent writes

Partial save, submit, abandon, and reopen accept expectedUpdatedAt from the last read. The comparison happens inside the write. A mismatch fails with STALE_UPDATE.

useSurveyResponse sends the token it last read. On STALE_UPDATE it sets stale and leaves the model mounted. Call reload to read the stored snapshot again.

Omit the token only when a last-write-wins update is intentional.

Read response lists

listResponses defaults to a summary. Summary rows omit definition and data. include: "full" returns the complete analytics snapshot and is only available to the editor audience.

Both lists default to 50 rows and cap at 100. Results sort by updatedAt descending. total ignores limit and offset.

submittedFrom and submittedTo are inclusive bounds on submittedAt. Rows with no submit time are excluded. updatedAfter is an exclusive lower bound on updatedAt.

Read full rows against definition on that row. Do not join them back to the live survey document.

On this page