Creating a new type
This page follows on from Getting started with plugin development and will show you how to finish the "angles-type" plug-in which adds an angular degrees data type to Saltcorn.
To define the functionality in a Saltcorn module, you add to the object that is exported from the main JavaScript file in the NPM package. The types
key in this object should hold a list of definitions of new datatypes. We start by adding the types key to the module:
module.exports = { sc_plugin_api_version: 1, types: [] };
This is still a blank module! To add our type definition in the types
array, I recommend introducing defining the type as a separate object before including in the array:
const angle= {
// ...
}
module.exports = { sc_plugin_api_version: 1, types: [angle] };
A valid object defining a new type should have the following keys:
name
: a string giving a short name to distinguish the new typesql_name
: a string indicating the data type by which the value will be stored in an SQL database.fieldviews
: an object of objects, each of which define a fieldview, that is a way for the user to see or edit a value of the new typeread
: a function which takes as an argument a JavaScript value of a variety of JavaScript types and outputs a valid JavaScript representation for a value of this type, orundefined
if the argument cannot be converted to a valid representation.
The type object can have the following keys, but these are not necessary:
attributes
: an array of objects specifying the attributes of the typevalidate
: a function from the attributes to a function from the JavaScript representation of the value to a Boolean. Indicates whether this value is valid within the parameters set by the attributes, if any.validate_attributes
: a function from the attributes as an object to a Boolean indicating whether these attributes are consistent and valid. Sometimes attributes can be invalid: for instance, number types have min and max attributes. A set of attributes are not valid if min > maxpresets
: a type can specify presets with an object of functions that return a JavaScript representation of the value. For instance, for instance, the presets for the date type includes a function that returns the current time. These presets can be used to auto populate form values.readFromFormRecord
: some datatypes can only be read from form values by reading the entire form. This is necessary to read Boolean values from form data, because an un-ticked checkbox is absent from the form results.readFromDB
: if the data needs to be transformed from the database representation to the JavaScript representation, specify the transformation here. This can be used to resolve inconsistencies between different database backends.
In the fieldviews
object, every key/value pair gives a new fieldview. The key is the name of the fieldview, and the value is an object containing two properties:
isEdit
: a Boolean (true
orfalse
). If true, this field view is for editing values; if false, this field view is for displaying valuesrun
: a function that returns a string containing the HTML required to display the fieldview of the value in a browser. The run function takes these arguments:- if
isEdit==false
: a single argument, the JavaScript representation of the value in the new data type. This will be the output of theread
function. - if
isEdit==true
: up to four arguments containing the information required to render a form input for the given data type. The arguments are:- 1st argument: the field name as a string. This should be the name of the form entry
- 2nd argument: the current value as a JavaScript representation. If there is no current value (for instance, this is a form creating a new row), the 2nd argument will be
undefined
- 3rd argument: an array of values for the attributes of this field.
- 4th argument: a class we are required to add as the class for the HTML element.
- if
Based on these definitions, we can start to build our angle
object describing our new type. It's always good to look at previous definitions. In our case, the Angle type will be very similar to the built-in type definition for floating-point numbers. This is defined in the main Saltcorn repository in the types.js file.
const angle = {
name: "Angle",
sql_name: "double precision",
fieldviews: {
show: { isEdit: false, run: (s) => `${s}°` },
edit: {
isEdit: true,
run: (nm, v, attrs, cls) =>
`<input type="number" class="form-control ${cls}" name="${nm}" id="input${nm}" ${
v || v === 0 ? `value="${v}"` : ""
}>°`,
},
},
read: (v) => {
switch (typeof v) {
case "number":
return v;
case "string":
const parsed = parseFloat(v);
return isNaN(parsed) ? undefined : parsed;
default:
return undefined;
}
},
};
module.exports = { sc_plugin_api_version: 1, types: [angle] };
This code provides the name, SQL name, field views and the read function needed to define the angle data type. In the run methods, we use JavaScript string interpolation to generate the HTML in order to reduce the number of concepts introducced in this tutorial. This is perfectly acceptable, but in other plug-ins we use the HTML combinator is from the @saltcorn/markup library. You can also use handlebars or any other form of templating system you are familiar with, as long as in the end you return a string containing the HTML. If the value contains strings provided by the user, you may also want to consider cross site scripting (XSS) protection.
Since you have now added something useful to the plug-in, you may want to go ahead and create a new release. If you want to upload to the NPM repository again, you must increase the version number specified in the package.json file. You cannot upload the same version twice.