Form

To build forms, you can use the form component. It offers a simple way to build forms in a consistent way only by passing a dictionary. Mainly it is used by the coordinator component, but it can also be used standalone.

<BasicForm
    ref="form"
    v-model="data"
    :fields="fields"
/>
import BasicForm from "@/basic/Form.vue";

export default {
    components: {
        BasicForm
    },
    data() {
        return {
            data: {},
            fields: {},
        }
    },
}

The formular is built from the properties of the object fields. It is a dictionary with basic keys to describe each part of the form. There are three kinds of properties:

  • Basic form properties - These properties are required for each field

  • Extended form properties - These properties are optional and are specific to different field types

  • Field specific properties - These properties are optional but are highly field specific

Basic form properties

Basic form properties

Key

Description

Required

Data Type

key

The key of the field in the data object

true

String

type

The type of the field (see Types for available types)

true

String

required

If the field is required (will be validated in frontend and backend)

false

Boolean

default

The default value of the field (data type depends on the field type)

false

Any

pattern

The regex pattern of the field that is checked if required

false

String

minLength

The minimum length of the field that is checked if required

false

Number

maxLength

The maximum length of the field that is checked if required

false

Number


Extended form properties

The properties of the fields object could be extended by the field specific properties. See the Types section for more information.

Extended form properties

Key

Description

Required

Default

Type

label

The label of the field shown in frontend

true

“”

String

disabled

If the switch should be disabled (also readOnly is possible)

false

false

Boolean

help

The help text shown in the near of the field

false

“”

String

placeholder

The placeholder text shown in the field

false

“”

String

class

The class of the field

false

“”

String

readOnly

Marks the field as read-only (used instead of or with disabled)

false

false

Boolean

suffix

Optional clickable icon/button inside input (e.g., for actions)

false

null

Object

Available extended properties in form fields

Type

label

disabled

help

placeholder

class

readOnly

suffix

text

Y

Y

Y

Y

Y

Y

Y

switch

Y

Y

Y

N

Y

Y

N

slider

Y

N

Y

N

Y

N

N

datetime

Y

N

Y

N

N

N

N

select

Y

N

Y

N

N

Y

N

checkbox

Y

N

Y

N

Y

Y

N

editor

Y

N

Y

N

N

N

N

textarea

Y

Y

Y

Y

Y

Y

N

table

Y

N

Y

N

N

N

N

password

Y

N

N

Y

Y

Y

N

file

Y

Y

Y

N

Y

Y

N

choice

Y

N

Y

N

N

N

N

default (*)

Y

Y

Y

Y

Y

Y

Y


Specific form properties

The following types are available:

Switch: No specific options.


Slider: Additional options:

  • min

  • max

  • step

  • unit — Optional unit label shown next to the current value.

  • textMapping — Array that maps numeric values to display labels.

    textMapping: [
        { from: 0, to: "Low" },
        { from: 1, to: "Medium" },
        { from: 2, to: "High" }
    ]
    

Datetime: No specific options.


Select: There are two ways to define the options of a select field, either by passing an object or use data from a autotable in (Vuex Store).

Passing an object:

{
    default: "info",
    options: [
        {
            name: "info",
            value: "info",
            class: "border border-info"
        },
        ...
    ]
}

Using autotable:

{
    options: {
        table: <tableName>,             // the name of the autotable in the vuex store
        name: <keyOfDisplayName>,       // the key of the display text used in the table entries
        value:<keyOfValueUsed>,         // the key of the value used in the table entries
        filter: [                       // -- optional - list of filters to apply to the table entries
            {
                type: <filterType>,    // the type of the filter
                key: <keyOfFilter>,     // the key in the table entries that should be filtered
                value: <valueOfFilter>  // the value that should be filtered for
                mapping: <mapObject>    // the real values will be used as key of this object, the output values as compared value
            }
        ],
    },
}

Checkbox: Each checkbox expects options.options to be an array of { label, value } objects.


Editor: See Editor for more information.

Note

You can also use html as type.


Textarea: No specific options.


Table: Tables are a bit more complex, example:

{
    key: "tags",
    label: "Tags:",
    type: "table",
    options: {
        table: "tag", id: "tagSetId"
    },
    required: true,
}

It shows the corresponding fields of the table tag and allows to add and remove rows. Only Select and Text fields are supported.


Password: No specific options.


File: The file field type allows uploading a file using a standard file input. It is typically used for attaching documents such as PDFs or Delta files in forms. The field stores the uploaded File object, which is then passed to the backend via socket communication.

Additional options:

  • accept — allowed MIME types (e.g. application/pdf, .delta)

  • class — custom input class

File uploads are handled via the documentAdd method in the document.js Socket.This is a special case because uploaded files are not just saved as form values but:

  1. Validated — only .pdf and .delta files are allowed.

  2. Stored to disk — files are written to the /files directory using a generated hash as filename.

  3. Stored in database — an entry is created in the document table with metadata like name, type, userId, etc.

For .delta files:

  • A document_edit entry is also created using content from the Delta format. See Delta Files and DB Edits for more information on how .delta files are stored and processed.

For .pdf files:

  • Existing annotations are removed via a server RPC (PDFRPC.deleteAllAnnotations).

  • If importAnnotations is set to true, new annotations are automatically extracted and saved.


Choice: The Choice component displays a dynamic list of items (choices) where each row can be configured individually. This component is useful when you want to collect structured data per entry—especially in workflows or assignments where each step or entity may have different options or linked configurations.

It renders a table layout and allows you to bind form fields per row.

While the options object often points to backend tables and filters (similar to how workflows are stored in the database), it’s important to understand that in the context of the Choice component, these keys control what is shown, editable, and validated in the UI:

  • table – Defines where the component stores and reads the selected/configured entries.

  • choices.table – Defines the source from which the list of available rows is loaded.

  • choices.filter – Controls which rows appear at all (static or dynamic rules).

  • choices.disabled – Prevents specific rows from being selectable or editable while keeping them visible if needed.

Tip

To better understand how the Choice component fits into a workflow, here’s a minimal example of how workflows are structured in the backend (see What is a Study? for further examples of study workflows):

[
  {
    "name": "Peer Review Workflow",
    "steps": [
      { "stepType": 1, "allowBackward": false },
      {
        "stepType": 2,
        "allowBackward": true,
        "configuration": {
          "fields": [
            { "name": "reviewLink" },
            { "name": "reviewText" }
          ]
        }
      }
    ]
  }
]

In this structure:

  • Each workflow contains multiple steps.

  • stepType defines the type of action (e.g., edit, review).

  • allowBackward determines if users can return to a step.

  • configuration holds extra options or fields for that step.

However, when using the Choice component, you are not editing this structure directly. Instead, you are selecting and configuring rows from a source list (choices.table) based on filters (choices.filter), and binding the results to your form via v-model.

Example usage:

<FormChoice
    v-model="workflowSteps"
    :options="{
        options: {
            table: 'workflow_step_assignment',
            choices: {
                table: 'workflow_step',
                filter: [
                    { type: 'formData', key: 'workflowId', value: 'workflowId' }
                ]
            }
        }
    }"
    @update:config-status="handleStatus"
/>
import FormChoice from '@/basic/form/Choice.vue';

export default {
    name: 'ChoiceExample',
    components: { FormChoice },
    data() {
        return {
            workflowSteps: [],
        };
    },
    methods: {
        handleStatus(status) {
            console.log("Config status:", status);
        },
    },
};
Choice properties

Prop

Description

Type

Required

modelValue

Two-way bound data array for all choices (stores the selected/configured rows).

Array

False

options

Configuration object that defines both: - The target table for storing selection/configuration. - The source and filtering logic for available choices.

Object

True

options.options.choices

Key

Description

table

Backend table from which the component loads available choices to display in the list.

filter

Rules controlling which rows are visible. Can be based on static values or dynamic form data.

disabled

Optional rules to hide or lock certain rows without removing them.

Tip

The component emits @update:config-status whenever one or more of the rows has incomplete configuration. It also provides a validate() method which can be called from the parent via a ref to ensure all required inputs are set.

While the backend table/field names come from the database model, their effect inside the Choice component is purely about what gets rendered, how it can be interacted with, and what gets sent back when saving.


Default: Basic HTML input from type specified in type if no other type matches. For example it is used for text.

Extended form properties

Key

Description

Required

name

The name of the input field

false

class

The css class of the input field

false

placeholder

The placeholder of the input field

false

Additional options:

  • suffix — Optional action button inside the input. Provide an object like:

    {
        suffix: {
            text: "Go",
            tooltip: "Click to trigger",
            onClick: () => { ... }
        }
    }
    
  • readOnly — If true, the field cannot be modified but remains visible.


Moodle Options

The MoodleOptions wraps a Basic Form to collect Moodle connection parameters and, optionally, an assignment ID. It is used inside StepperModal workflows such as:

  • Importing submissions from Moodle

  • Publishing review links

  • Bulk user creation with upload to Moodle

Example usage:

<MoodleOptions
  ref="moodleOptionsForm"
  v-model="moodleOptions"
  with-assignment-id
/>

Field visibility and defaults are driven by admin settings (rpc.moodleAPI.*). Assignment IDs can be fetched live from Moodle via a Refresh button, which triggers a backend request (assignmentGetInfo). For the end-to-end researcher workflow, see ../../for_researchers/moodle_usage.