Authoring Custom Questions & Features

Please see Getting Started with Custom Questions and Features before starting with your Custom Question project.

We recommend using the Custom Question Skeleton project to build your Custom Question.

This page describes how to set up default schemas rules as well as the desired editor layout for your custom Question or Feature with Learnosity Question Editor API.

Overview

In order to build a Custom Question / Feature, you need to do the following:

  1. Define a schema for the Question Editor form (JSON data),
  2. Provide a corresponding HTML layout, which contains the hooks which Question Editor uses to insert the schema attributes (HTML file),
  3. Provide the custom question logic (JS file) which contains logic to parse the Question JSON and render the Question, and
  4. Provide the custom scoring logic (JS file) which contains logic to score the learner's response.

In this article, we'll look into some different examples for the schema and the HTML layout (points one and two above) - covering a simple static form, a dynamic example and a more advanced dynamic example.

Please refer to Creating Custom Questions for information on the custom Question and scoring logic (points 3 and 4 above).

Custom Question / Feature Schemas

In order for the Question Editor to understand what desired input types you want to use when authoring your custom Question or Feature, you need to define the schema for each input.

The rule will be inserted through the custom_question_types and custom_feature_types initialization options.

Each entry in the array will define some properties including the JavaScript and the layout, see more information on the docs pages linked above.

The schemas are defined in the property editor_schema.

Understanding editor_schema

The editor_schema defines the authoring interface for a Custom Question or Feature. It specifies the attributes that authors can configure, how those attributes are displayed in the Question Editor, and how their values are stored in the Question JSON.

The Question Editor uses the editor_schema to:

  • Generate the authoring interface
  • Validate author input
  • Store attribute values in the Question JSON

The editor_schema defines the configurable attributes for the Custom Question or Feature. The editor_layout, when supplied, defines where those attributes are rendered in the Question Editor. For more information, see Adding a Custom Editor Layout for a Question Type.

Note: The Question Editor supports both attributes and properties within editor_schema. They are functionally equivalent because properties is translated internally by the Question Editor. New implementations should use attributes, which is the canonical form used throughout the Learnosity documentation.

Supported schema attribute types

Every attribute defined within editor_schema.attributes (or editor_schema.properties) must specify a type.

Type Description
string Simple text input.
number Numeric input. Only numeric values are accepted.
boolean Checkbox/toggle control.
editor Rich text editor.
question Renders the current Custom Question using the supplied white_list attributes. This is commonly used when authoring validation responses.
array Repeatable collection of attributes. Requires the items property.
object Groups related attributes together and supports nested attribute structures.

The type determines the data model for the attribute. You can optionally specify an element to change how that attribute is rendered in the Question Editor.

Supported editor elements

The optional element property overrides the default editor control used for an attribute.

Element Description
select Displays a dropdown list. Requires the options property.
colorPicker Displays a colour picker. Supported only with type: "string".
question Renders the current Question using the supplied white_list.
array Used only when type is array. No other element values are supported for arrays.

For example, a dropdown is defined as:

{
   "type": "string",
   "element": "select",
   "options": [
       {
           "label": "Display text",
           "value": "stored_value"
       }
   ]
}

Common editor_schema properties

Property Required Description
type Yes Specifies the attribute type.
name Recommended Label displayed in the Question Editor.
description No Additional help text displayed to authors.
element No Overrides the default editor control.
required No Requires the author to enter a value before saving.
default No Default value used when creating a Question.
group No Groups attributes in automatically generated layouts.
options Required when element is select.
items Required when type is array.
attributes Required when type is object.
white_list Required when type or element is question.
min No Minimum value for number attributes.
editorV3 No Question Editor V3-specific overrides.

Validation rules

The Question Editor validates the editor_schema before allowing a Question to be saved. Depending on the schema configuration, the following validation rules apply:

  • type: "number" accepts only numeric values.
  • required: true requires a value before the Question can be saved.
  • min: "number" enforces the minimum numeric value.
  • element: "select" requires the options property.
  • type: "array" requires the items property.

Static attributes

Static forms are easily achievable using the schemas rules mentioned above. To see an example of this, along with the schema and the layout, please see our demo for the custom Question, using a box & whisker chart.

Dynamic attributes

It is possible to create dynamic forms using conditional_attributes. That is, you can have attributes which only appear when another attributes value is a specific value.

If you want to have nested conditionals, that is, attributes which are shown based on the value if another attribute, which itself is shown based on the attribute of another, then the properties must be nested themselves.

For single level conditionals the output JSON can remain flat, but if if you have nested, then the JSON will have nested attributes.

To understand further, see the following two examples.

Referencing nested attributes

Nested attributes are defined using type: "object" and referenced using dot notation.

Example schema:

{
   "validation": {
       "type": "object",
       "attributes": {
           "valid_response": {
               "type": "object",
               "attributes": {
                   "score": {
                       "type": "number"
                   }
               }
           }
       }
   }
}

Nested attributes are referenced using their full attribute path.

Example:

<span data-lrn-qe-input="validation.valid_response.score"></span>

For array attributes, use the [*] wildcard within data-lrn-qe-loop.

Example:

<div data-lrn-qe-loop="validation.alt_responses[*]">
   <span data-lrn-qe-input="validation.alt_responses[*].score"></span>
</div>

Basic Example

In this example, we have a dropdown menu to select types of triangle. When one is selected, different fields show based on that value. For example, for equilateral, as all sides are the same length, there's just one field for "Side length" which appears. Whereas for scalene, as all three sides are different lengths, three fields (array) are shown. See the video below which demonstrates this, and below that are the code examples for the schema, HTML and output JSON.

 
Video 1: basic dynamic form

Schema data

{
    "editor_schema": {
        "hidden_question": false,
        "attributes": {
            "stimulus": {
                "type": "string",
                "name": "Stimulus",
                "description": "The question for the student to answer",
                "required": true,
                "element": "editor",
                "default": "Calculate the area of the shape below"
            },
            "triangle_type": {
                "type": "string",
                "name": "Triangle Type",
                "description": "Select a type of triangle.",
                "required": true,
                "element": "select",
                "options": [{
                    "value": "equilateral",
                    "label": "Equilateral"
                }, {
                    "value": "isosceles",
                    "label": "Isosceles"
                }, {
                    "value": "scalene",
                    "label": "Scalene"
                }, {
                    "value": "right",
                    "label": "Right Angled"
                }],
                "default": "equilateral"
            },
            "color": {
                "type": "string",
                "name": "Color",
                "description": "Fill color of the shape.",
                "required": true,
                "element": "colorPicker",
                "default": "#0f3d6d"
            }
        },
        "conditional_attributes": {
            "attribute_key": "triangle_type",
            "conditions": [{
                "value": "equilateral",
                "attributes": {
                    "side_length": {
                        "type": "number",
                        "name": "Side Length (cm)",
                        "description": "Length of the side of the triangle.",
                        "required": true
                    }
                }
            }, {
                "value": "isosceles",
                "attributes": {
                    "base": {
                        "type": "number",
                        "name": "Base",
                        "description": "Base length of the triangle.",
                        "required": true
                    },
                    "height": {
                        "type": "number",
                        "name": "Side Length",
                        "description": "Length of the equal sides of the triangle.",
                        "required": true
                    }
                }
            }, {
                "value": "scalene",
                "attributes": {
                    "side_lengths": {
                        "items": {
                            "type": "number",
                            "name": "Side length "
                        },
                        "name": "Side Lengths",
                        "description": "Lengths of the sides of the triangle.",
                        "required": true,
                        "type": "array",
                        "count": {
                            "minimum": 3,
                            "maximum": 3
                        }
                    }
                }
            }, {
                "value": "right",
                "attributes": {
                    "base": {
                        "type": "number",
                        "name": "Base",
                        "description": "Base length of the triangle.",
                        "required": true
                    },
                    "height": {
                        "type": "number",
                        "name": "Height",
                        "description": "Height of the triangle.",
                        "required": true
                    }
                }
            }]
        }
    }
}

Source code example 1: the schema data

HTML layout

<div class="lrn-qe-edit-form">
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <span data-lrn-qe-label="stimulus"></span><span data-lrn-qe-input="stimulus"></span>
    </div>
    <!-- triangle -->
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <span data-lrn-qe-label="triangle_type"></span><span data-lrn-qe-input="triangle_type"></span>
    </div>
    <!-- equilateral -->
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <span data-lrn-qe-label="side_length"></span><span data-lrn-qe-input="side_length"></span>
    </div>
    <!-- isosceles -->
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <span data-lrn-qe-label="base"></span><span data-lrn-qe-input="base"></span>
    </div>
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper><span data-lrn-qe-label="height"></span>
        <span data-lrn-qe-input="height"></span>
    </div>
    <!-- scalene -->
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <div data-lrn-qe-loop="side_lengths[*]">
            <div data-lrn-qe-label="side_lengths[*]"></div>
            <div data-lrn-qe-input="side_lengths[*]"></div>
        </div>
    </div>
    <!-- color -->
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <span data-lrn-qe-label="color"></span><span data-lrn-qe-input="color"></span>
    </div>
</div>

Source code example 2: the HTML layout

Example JSON (for a scalene triangle)

{
    "type": "custom",
    "stimulus": "Calculate the area of the shape below",
    "js": {
        "question": "shapes_q.js",
        "scorer": "shapes_s.js"
    },
    "valid_response": 1.9843,
    "score": 1,
    "custom_type": "custom",
    "css": "custom.css",
    "version": "v1.0.0",
    "triangle_type": "scalene",
    "color": "#0f3d6d",
    "side_lengths": [2, 3, 2]
}

Source code example 3: the JSON source for the scalene example

Advanced Example

In this example, we have a select dropdown where the shape dimensions is picked first (2D/3D), then based on that another drop-down menu shows different classifications of shapes (Triangle, Quadrilateral, etc.), and then based on that different shape types are shown (Square, Scalene, and so on).
See the video below which demonstrates this, and below that are the code examples for the schema, HTML and output JSON.

 
Video 2: advanced dynamic form

Schema data

{
    "editor_schema": {
        "hidden_question": false,
        "attributes": {
            "stimulus": {
                "type": "string",
                "name": "Stimulus",
                "description": "The question for the student to answer",
                "required": true,
                "element": "editor",
                "default": "Calculate the [area/volume] of the shape below"
            },
            "dimensions": {
                "type": "string",
                "name": "Shape Dimensions",
                "description": "Select the type of shape.",
                "required": true,
                "element": "select",
                "options": [{
                    "value": "2d",
                    "label": "2D"
                }, {
                    "value": "3d",
                    "label": "3D"
                }],
                "default": "3d"
            },
            "color": {
                "type": "string",
                "name": "Color",
                "description": "Fill color of the shape.",
                "required": true,
                "element": "colorPicker",
                "default": "#0cb0d8"
            }
        },
        "conditional_attributes": {
            "attribute_key": "dimensions",
            "conditions": [{
                "value": "2d",
                "attributes": {
                    "2d": {
                        "type": "object",
                        "attributes": {
                            "shape": {
                                "type": "string",
                                "name": "2D Shape",
                                "description": "Select a 2D shape.",
                                "required": true,
                                "element": "select",
                                "options": [{
                                    "value": "quadrilateral",
                                    "label": "Quadrilateral"
                                }, {
                                    "value": "triangle",
                                    "label": "Triangle"
                                }, {
                                    "value": "polygon",
                                    "label": "Polygon"
                                }],
                                "default": "triangle"
                            }
                        },
                        "conditional_attributes": {
                            "attribute_key": "shape",
                            "conditions": [{
                                "value": "quadrilateral",
                                "attributes": {
                                    "quadrilateral": {
                                        "type": "object",
                                        "attributes": {
                                            "type": {
                                                "type": "string",
                                                "name": "Quadrilateral Type",
                                                "description": "Select a type of quadrilateral.",
                                                "required": true,
                                                "element": "select",
                                                "options": [{
                                                    "value": "square",
                                                    "label": "Square"
                                                }, {
                                                    "value": "rectangle",
                                                    "label": "Rectangle"
                                                }, {
                                                    "value": "rhombus",
                                                    "label": "Rhombus"
                                                }],
                                                "default": "square"
                                            }
                                        },
                                        "conditional_attributes": {
                                            "attribute_key": "type",
                                            "conditions": [{
                                                "value": "square",
                                                "attributes": {
                                                    "square_options": {
                                                        "type": "object",
                                                        "name": "Square Options",
                                                        "description": "Options for squares.",
                                                        "required": true,
                                                        "attributes": {
                                                            "side_length": {
                                                                "type": "number",
                                                                "name": "Side Length",
                                                                "description": "Length of the side of the square.",
                                                                "required": true
                                                            }
                                                        }
                                                    }
                                                }
                                            }, {
                                                "value": "rectangle",
                                                "attributes": {
                                                    "rectangle_options": {
                                                        "type": "object",
                                                        "name": "Rectangle Options",
                                                        "description": "Options for rectangles.",
                                                        "required": true,
                                                        "attributes": {
                                                            "length": {
                                                                "type": "number",
                                                                "name": "Length",
                                                                "description": "Length of the rectangle.",
                                                                "required": true
                                                            },
                                                            "width": {
                                                                "type": "number",
                                                                "name": "Width",
                                                                "description": "Width of the rectangle.",
                                                                "required": true
                                                            }
                                                        }
                                                    }
                                                }
                                            }, {
                                                "value": "rhombus",
                                                "attributes": {
                                                    "rhombus_options": {
                                                        "type": "object",
                                                        "name": "Rhombus Options",
                                                        "description": "Options for rhombuses.",
                                                        "required": true,
                                                        "attributes": {
                                                            "side_length": {
                                                                "type": "number",
                                                                "name": "Side Length",
                                                                "description": "Length of the side of the rhombus.",
                                                                "required": true
                                                            },
                                                            "angle": {
                                                                "type": "number",
                                                                "name": "Angle",
                                                                "description": "Angle of the rhombus.",
                                                                "required": true
                                                            }
                                                        }
                                                    }
                                                }
                                            }]
                                        }
                                    }
                                }
                            }, {
                                "value": "triangle",
                                "attributes": {
                                    "triangle": {
                                        "type": "object",
                                        "attributes": {
                                            "type": {
                                                "type": "string",
                                                "name": "Triangle Type",
                                                "description": "Select a type of triangle.",
                                                "required": true,
                                                "element": "select",
                                                "options": [{
                                                    "value": "equilateral",
                                                    "label": "Equilateral"
                                                }, {
                                                    "value": "isosceles",
                                                    "label": "Isosceles"
                                                }, {
                                                    "value": "scalene",
                                                    "label": "Scalene"
                                                }, {
                                                    "value": "right",
                                                    "label": "Right Angled"
                                                }],
                                                "default": "equilateral"
                                            }
                                        },
                                        "conditional_attributes": {
                                            "attribute_key": "type",
                                            "conditions": [{
                                                "value": "equilateral",
                                                "attributes": {
                                                    "equilateral_options": {
                                                        "type": "object",
                                                        "name": "Equilateral Options",
                                                        "description": "Options for equilateral triangles.",
                                                        "required": true,
                                                        "attributes": {
                                                            "side_length": {
                                                                "type": "number",
                                                                "name": "Side Length (cm)",
                                                                "description": "Length of the side of the triangle.",
                                                                "required": true
                                                            }
                                                        }
                                                    }
                                                }
                                            }, {
                                                "value": "isosceles",
                                                "attributes": {
                                                    "isosceles_options": {
                                                        "type": "object",
                                                        "name": "Isosceles Options",
                                                        "description": "Options for isosceles triangles.",
                                                        "required": true,
                                                        "attributes": {
                                                            "base": {
                                                                "type": "number",
                                                                "name": "Base",
                                                                "description": "Base length of the triangle.",
                                                                "required": true
                                                            },
                                                            "side_length": {
                                                                "type": "number",
                                                                "name": "Side Length",
                                                                "description": "Length of the equal sides of the triangle.",
                                                                "required": true
                                                            }
                                                        }
                                                    }
                                                }
                                            }, {
                                                "value": "scalene",
                                                "attributes": {
                                                    "scalene_options": {
                                                        "type": "object",
                                                        "name": "Scalene Options",
                                                        "description": "Options for scalene triangles.",
                                                        "required": true,
                                                        "attributes": {
                                                            "side_lengths": {
                                                                "items": {
                                                                    "type": "number",
                                                                    "name": "Side length "
                                                                },
                                                                "name": "Side Lengths",
                                                                "description": "Lengths of the sides of the triangle.",
                                                                "required": false,
                                                                "type": "array",
                                                                "count": {
                                                                    "minimum": 3,
                                                                    "maximum": 3
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }, {
                                                "value": "right",
                                                "attributes": {
                                                    "right_options": {
                                                        "type": "object",
                                                        "name": "Right Options",
                                                        "description": "Options for right triangles.",
                                                        "required": true,
                                                        "attributes": {
                                                            "base": {
                                                                "type": "number",
                                                                "name": "Base",
                                                                "description": "Base length of the triangle.",
                                                                "required": true
                                                            },
                                                            "height": {
                                                                "type": "number",
                                                                "name": "Height",
                                                                "description": "Height of the triangle.",
                                                                "required": true
                                                            }
                                                        }
                                                    }
                                                }
                                            }]
                                        }
                                    }
                                }
                            }, {
                                "value": "polygon",
                                "attributes": {
                                    "type": "object",
                                    "polygon": {
                                        "attributes": {
                                            "type": {
                                                "type": "string",
                                                "name": "Polygon Type",
                                                "description": "Select a type of polygon.",
                                                "required": true,
                                                "element": "select",
                                                "options": [{
                                                    "value": "pentagon",
                                                    "label": "Pentagon"
                                                }, {
                                                    "value": "hexagon",
                                                    "label": "Hexagon"
                                                }, {
                                                    "value": "octagon",
                                                    "label": "Octagon"
                                                }],
                                                "default": "pentagon"
                                            }
                                        },
                                        "conditional_attributes": {
                                            "attribute_key": "type",
                                            "conditions": [{
                                                "value": "pentagon",
                                                "attributes": {
                                                    "pentagon_options": {
                                                        "type": "object",
                                                        "name": "Pentagon Options",
                                                        "description": "Options for pentagons.",
                                                        "required": true,
                                                        "attributes": {
                                                            "side_length": {
                                                                "type": "number",
                                                                "name": "Side Length",
                                                                "description": "Length of the side of the pentagon.",
                                                                "required": true
                                                            }
                                                        }
                                                    }
                                                }
                                            }, {
                                                "value": "hexagon",
                                                "attributes": {
                                                    "hexagon_options": {
                                                        "type": "object",
                                                        "name": "Hexagon Options",
                                                        "description": "Options for hexagons.",
                                                        "required": true,
                                                        "attributes": {
                                                            "side_length": {
                                                                "type": "number",
                                                                "name": "Side Length",
                                                                "description": "Length of the side of the hexagon.",
                                                                "required": true
                                                            }
                                                        }
                                                    }
                                                }
                                            }, {
                                                "value": "octagon",
                                                "attributes": {
                                                    "octagon_options": {
                                                        "type": "object",
                                                        "name": "Octagon Options",
                                                        "description": "Options for octagons.",
                                                        "required": true,
                                                        "attributes": {
                                                            "side_length": {
                                                                "type": "number",
                                                                "name": "Side Length",
                                                                "description": "Length of the side of the octagon.",
                                                                "required": true
                                                            }
                                                        }
                                                    }
                                                }
                                            }]
                                        }
                                    }
                                }
                            }]
                        }
                    }
                }
            }, {
                "value": "3d",
                "attributes": {
                    "3d": {
                        "type": "object",
                        "attributes": {
                            "shape": {
                                "type": "string",
                                "name": "3D Shape",
                                "description": "Select a 3D shape.",
                                "required": true,
                                "element": "select",
                                "options": [{
                                    "value": "polyhedron",
                                    "label": "Polyhedron"
                                }, {
                                    "value": "sphere",
                                    "label": "Sphere"
                                }, {
                                    "value": "cylinder",
                                    "label": "Cylinder"
                                }, {
                                    "value": "cone",
                                    "label": "Cone"
                                }],
                                "default": "polyhedron"
                            }
                        },
                        "conditional_attributes": {
                            "attribute_key": "shape",
                            "conditions": [{
                                "value": "polyhedron",
                                "attributes": {}
                            }]
                        }
                    }
                }
            }]
        }
    }
}

Source code example 4: schema data for the advanced example

HTML layout (not all included for brevity)

<div class="lrn-qe-edit-form">
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <span data-lrn-qe-label="stimulus"></span>
        <span data-lrn-qe-input="stimulus"></span>
    </div>
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
      	<span data-lrn-qe-label="dimensions"></span>
      	<span data-lrn-qe-input="dimensions"></span>
  	</div>
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
      	<span data-lrn-qe-label="2d.shape"></span>
      	<span data-lrn-qe-input="2d.shape"></span>
  	</div>
    <!-- 2D --><!-- quadrilateral -->
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <span data-lrn-qe-label="2d.quadrilateral.type"></span>
        <span data-lrn-qe-input="2d.quadrilateral.type"></span>
    </div>
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <span data-lrn-qe-label="2d.quadrilateral.square_options.side_length"></span>
        <span data-lrn-qe-input="2d.quadrilateral.square_options.side_length"></span>
    </div>
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <span data-lrn-qe-label="2d.quadrilateral.square_options.color"></span>
        <span data-lrn-qe-input="2d.quadrilateral.square_options.color"></span>
    </div>
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <span data-lrn-qe-label="2d.quadrilateral.rectangle_options.length"></span>
        <span data-lrn-qe-input="2d.quadrilateral.rectangle_options.length"></span>
    </div>
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <span data-lrn-qe-label="2d.quadrilateral.rectangle_options.width"></span>
        <span data-lrn-qe-input="2d.quadrilateral.rectangle_options.width"></span>
    </div>
    <div class="lrn-qe-col-lg-12" data-lrn-qe-layout-wrapper>
        <span data-lrn-qe-label="2d.quadrilateral.rectangle_options.color"></span>
        <span data-lrn-qe-input="2d.quadrilateral.rectangle_options.color"></span>
    </div>
    ....
</div>

Source code example 5: HTML layout for the advanced example

JSON source (for the 3D -> polyhedron -> cube)

{
    "type": "custom",
    "js": {
        "question": "shapes_q.js",
        "scorer": "shapes_s.js"
    },
    "custom_type": "custom",
    "css": "custom.css",
    "version": "v1.0.0",
    "dimensions": "3d",
    "color": "#0cb0d8",
    "3d": {
        "polyhedron": {
            "cube_options": {
                "edge_length": 3
            }
        }
    }
}

Source code example 6: JSON for the 3D polyhedron cube

JSON source (for the 2D -> polyhedron -> cube)

{
    "type": "custom",
    "stimulus": "Calculate the [area/volume] of the shape below",
    "js": {
        "question": "shapes_q.js",
        "scorer": "shapes_s.js"
    },
    "custom_type": "custom",
    "css": "custom.css",
    "version": "v1.0.0",
    "dimensions": "2d",
    "color": "#0cb0d8",
    "2d": {
        "shape": "quadrilateral",
        "quadrilateral": {
            "type": "rectangle",
            "rectangle_options": {
                "length": 1,
                "width": 4
            }
        }
    }
}

Source code example 7: JSON for the 2D polyhedron cube

Schema limitations

The following limitations apply when defining an editor_schema:

  • Object nesting has no practical depth limit.
  • Arrays of objects are supported.
  • Nested arrays are supported.
  • white_list supports only top-level attribute names. Nested attribute paths (for example, validation.valid_response.score) cannot be specified in white_list.
  • conditional_attributes can only be defined at the root level of the editor_schema.

How to Create Custom Question / Feature Custom Tile Items

Once the custom Question / Feature is defined through custom_question_types and custom_feature_types, we can now reference those custom Questions / Features in question_type_templates through their custom_type unique IDs.

Defining Custom Question / Feature Tile Items

const initOptions = {
    custom_question_types: [{
        "custom_type": "custom_short_text",
        "type": "custom",
        "name": "Custom Shorttext (DRAFT)",
        "js": {
            "question": "//demos.learnosity.com/usecases/customquestions/custom_shorttext_q.js",
            "scorer": "//demos.learnosity.com/usecases/customquestions/custom_shorttext_s.js"
        },
        "css": "//demos.learnosity.com/usecases/customquestions/custom_shorttext.css",
        "editor_layout": "//demos.learnosity.com/usecases/customquestions/custom_shorttext.html",
        "version": "v0.1.0",
        "editor_schema": {
            "hidden_question": false,
            "properties": {
                "valid_response": {
                    "type": "string",
                    "name": "Valid response",
                    "description": "Correct answer for the question.",
                    "required": false
                },
                "score": {
                    "type": "number",
                    "name": "Score",
                    "description": "Score for a correct answer.",
                    "required": false,
                    "default": 0
                }
            }
        }
    }],

    custom_feature_types: [{
        "custom_type": "name_of_custom_type",
        "name": "Display Name of Custom Feature",
        "js": "//[your.domain]/myfeaturescript.js",
        "css": "//[your.domain]/myfeaturestyles.css",
        "version": "1.0.0",
        "editor_layout": "//[your.domain]/myquestioneditorlayout.html",
        "editor_schema": {
            "hidden_question": false,
            "properties": {
                "placeholder_text": {
                    "type": "string",
                    "required": false
                }
            }
        }
    }],

    question_type_templates: {
        custom_short_text: [{
            "name": "Custom Question - Short text",
            "description": "A custom question type - short text",
            "group_reference": "other",
            "image": "custom_image_link_of_your_custom_question_tile_item",
            "defaults": {
                "type": "custom",
                "js": {
                    "question": "//demos.learnosity.com/usecases/customquestions/custom_shorttext_q.js",
                    "scorer": "//demos.learnosity.com/usecases/customquestions/custom_shorttext_s.js"
                },
                "css": "//demos.learnosity.com/usecases/customquestions/custom_shorttext.css",
                "valid_response": "",
                "score": 1
            }
        }],
        custom_text_input_feature: [{
            "name": "Custom Feature - Simple textinput",
            "description": "A custom feature type - simple textinput",
            "image": "custom_image_link_of_your_custom_feature_tile_item",
            "defaults": {
                "type": "customfeature",
                "js": "//learnosity.github.io/docs-learnosity-apis/examples/custom_feature_types/textinput/index.js",
                "css": "//learnosity.github.io/docs-learnosity-apis/examples/custom_feature_types/textinput/index.css",
                "placeholder": "Default placeholder"
            }
        }]
    }
};

Source code example 8: Defining Custom Question / Feature Tile Items

Best practices

When defining an editor_schema:

  • Use attributes instead of properties. Although both are supported, attributes is the canonical form.
  • Use snake_case when naming custom attributes to remain consistent with Learnosity Question schemas.
  • Avoid custom attribute names that conflict with reserved attributes such as type, custom_type, js, css, and version.
  • Use group to organise automatically generated layouts.
  • Use type: "object" to organise related attributes into logical groups.
  • Use type: "array" together with items for repeatable collections of attributes.
  • Use conditional_attributes to dynamically show or hide attributes based on the value of another attribute.
  • Reuse supported native Question attributes (for example, stimulus, validation, and instant_feedback) when your Custom Question requires the same platform functionality.
Was this article helpful?

Did you arrive here by accident? If so, learn more about Learnosity.