Options

When building forms, there are many cases where you will want to present the end user with a list of options from which a value can be selected. The Options class is available in the Node.js libraries for Editor to fulfill this need. It is attached to an individual field using Field.options() and will resolve, based on its configuration, to a list of options for the field.

The following built-in field types can make use of the resulting options:

Options class

The Options class allows the list of options to be retrieved in a number of different ways:

  • From a database
  • A statically defined list of options
  • A custom function

The class also has a number of control methods available to define how it should operate for actions such as autocomplete and tags search, label display rendering and so on. See the "Control methods" section below for more details.

Attaching to a field

Each field in an Editor instance can have an Options class assigned to it through its Field.options() method - e.g.:

Field.options( new Options () )

Constructor

The constructor can be given with the following overloads:

  • new Options() - Empty initialisation, use the class methods to define behaviour.
  • new Options(table: string, value: string, label: string) - Set the most common database options in the constructor.
  • new Options(fn) - Set a custom function to get the options.

The result is that the following two instances are equivalent:

new Options(table, value, label);

new Options()
    .table(table)
    .value(value)
    .label(label);

Database methods

The most common use for the Options class is to read a list of options from a database. The following methods are available to configure that interaction. Please note that when used as a setter (as described here), all methods return the class instance to allow easy chaining of methods.

label()

.label( label: string|string[] ): Options

Specify the column(s) that should be used for the label of an option pair (label/value). This is what the end user would see in the list of options. In many cases (but not all!) the label and value are not the same value - the value might be a row identifier, while the label is a human readable representation.

If given as a string, multiple columns will be read and can be used in the .render() function to present a label of arbitrary complexity.

leftJoin()

.leftJoin( table: string, column1: string, operator: string, column2: string ): Options

Provides a join to a second database table, allowing extra information to be looked up (typically for the label if needed). This method has the same signature as the Editor.leftJoin() method and directly maps to an SQL left join statement.

table()

.table( table: string ): Options

Set the database table name that the list options should be read from.

value()

.value( val: string ): Options

Set the column name that contains the value for each option pair (label/value). Typically this would be a primary key column in the table.

where()

.where( condition: callable ): Options

Function that will apply conditions to the list of options (i.e. a WHERE statement), allowing only a sub-set of the options to be selected. Please refer to the Knex.js documentation for full details of the conditional methods that can be used in this function.

Custom data methods

The following methods can be used to obtain the data for the options from a location other than a database.

add()

.add( label: string, value: string ): Options

Add static options to the list. This can be used alongside the database methods listed above to combine static options and the database retrieved data, or it can be used on its own. Note that the options here are passed through the rendering, options limit and ordering (i.e. the merge of static and database options is done before those operations are performed).

fn()

.fn( func: Function ): Options

This is function that takes two parameters:

  1. A Database object which can be used to perform custom lookups if needed (e.g. against a stored procedure or for cases with a complex query is required that cannot be constructed with the methods above).
  2. A search terms - used for the autocomplete and tags field types. The function should limit the returned options objects to those that match this term (can be null if no filtering is needed).

The return should be an array of objects, which contain label and value properties. Please note that unlike .add() the options returned by this method do not get merged with those from the database. This method provides you with complete control of the options to return to the client-side, and thus does not do any ordering or rendering.

Control methods

The following methods are used to control the operations that the Options class performs.

alwaysRefresh()

.alwaysRefresh( set: boolean ): Options

Set the flag to indicate if the options should always be refreshed (i.e. on get, create and edit) or only on the initial data load (false). Default is true (always refresh) and allows the list of options to take account of any changes that an editing action might cause (e.g. a new option, change in label, etc). The benefit of disabling this option is that one less query is performed on editing actions, which can help (albeit only a small amount) with performance, if you know the list of options won't change.

render()

.render( renderer: callable ): Options

A formatting function that will be applied to each label read from the database this is particularly useful if you get multiple columns with .label() and wish to customise how those fields are shown. They will simply be concatenated with a single space character if no function is provided. The function is called once for each option and is passed the database row for the option in question. A string must be returned.

include()

.include( column: string|string[] ): Options

By default the object for each option will contain only label and value properties, but you may wish to have extra information, particularly if you are doing client-side rendering for the labels. This method lets you specify column names from value() and label() that should be included in the output object for each option, in addition to the value and label.

limit()

.limit( set: integer ): Options

Limit the number of results that are returned. If this method is not used, no limit will be imposed.

order()

.order( set: string|boolean ): Options

Specify an SQL order by clause that will determine the order of the options. If this method is not used the ordering will be automatically performed on the rendered data (which is the same as passing in true). Ordering can be disabled by passing false to this method (since 2.4).

searchOnly()

.searchOnly( set: boolean ): Options

By default options will be read and returned for any field that has an Options class assigned to it. In the majority of cases this is what you want (e.g. select), but in some cases, the options might only be relevant once the user starts typing. You may wish to have this behaviour when using the built-in autocomplete and tags field types.

Examples

The following example shows the most simple used case with a list of options returned from the sites database table:

new Field('users.site')
    .options(
        new Options('sites, 'id', 'name')
    );

Using the chaining API, the same can be written as:

new Field('users.site')
    .options(new Options()
        .table('sites')
        .value('id')
        .label('name')
    );

To apply a condition to the data retrieval we can make use of the .where() method. In the below, getting only names which start with the letter 'L':

new Field('users.site')
    .options(new Options()
        .table('sites')
        .value('id')
        .label('name')
        .where(function() {
            this.where('name', 'LIKE', 'L%')
        })
    );

The following makes use of a rendering function to combine multiple fields for display as the label. In this case the resulting format is: 'name (country)' - e.g.: 'Edinburgh (UK)':

new Field('users.site')
    .options(new Options()
        .table('sites')
        .value('id')
        .label(['name', 'country'])
        .render(row => {
            return row.name + ' (' + row.country + ')';
        })
    );

Custom function

As a closure function, the Options provides the ability to get the data for the field options from virtually anywhere (files, arrays, web-services, database, etc) - you define the code that will return an array of options. By default the returned array should contain value/label options for each entry (although this can be customised using the options of the fields such as select).

The following example shows a static array of values being returned:

new Field('users.site').options(() => {
    return [
        {value: 'EDI', label: 'Edinburgh'},
        {value: 'LON', label: 'London'},
        {value: 'NEW', label: 'New York'},
        {value: 'SAN', label: 'San Francisco'}
    ];
});

Node.js API documentation

The Node.js API developer documentation for the Editor Node.js classes is available for detailed and technical discussion about the methods and classes discussed above.