Events

When working with complex data, it can often be useful to perform some additional action when Editor updates the database based on information from the client-side. Consider for example the following use case:

  • Modifying the Editor instance or form fields based on that action being taken
  • Deleting files from the file system when rows are removed
  • Logging information to a database about an action that a user has taken.

to name just a few!

To make this possible, the Node.JS Editor class provides an event listener / callback option similar to the events that the client-side Javascript will trigger.

Listening for events

Events listeners can be added using the Editor.on() method which takes two arguments:

  1. The event name to listen for
  2. A callback function which defines the action to take. The arguments passed to the callback are event dependent. The return value for the pre* named events can be used to cancel actions (see below), while the other event handlers to not use any returned value.

Multiple listeners for the same event can be added simply by calling the Editor.on() method multiple times. The events will be executed in the same sequence that they were added.

Available events

The Editor class will trigger the following events - the arguments passed into the function are also documented (please note that the events are shown below in the order that they are triggered for each action):

Get

  • preGet (cancellable) - Triggered immediately prior to reading row data from the database
    1. editor - The Editor instance that triggered the event
    2. id - Row id being selected if only a single row is to be selected (i.e. after an edit). Otherwise this value will be null indicating that all rows will be selected.
  • postGet - Triggered immediately after row information has been read from the database
    1. editor - The Editor instance that triggered the event
    2. id - Row id being selected if only a single row is to be selected (i.e. after an edit). Otherwise this value will be null indicating that all rows will be selected.
    3. data - Data array of rows that have been read from the database

Create

  • preCreate (cancellable) - Triggered prior to creating a new row and before validation has occurred, allowing extra validation to be added or values to be set
    1. editor - The Editor instance that triggered the event
    2. values - The values submitted by the client-side
  • validatedCreate - Triggered immediately prior to creating a new row, after validation has occurred (since 1.9.3)
    1. editor - The Editor instance that triggered the event
    2. values - The values submitted by the client-side
  • writeCreate - Data has been written to the database, but not yet read back, allowing the database to be updated before the data is gathered to display in the table
    1. editor - The Editor instance that triggered the event
    2. id - ID of the row that was created
    3. values - The values submitted by the client-side
  • postCreate - Triggered immediately after a new row has been created
    1. editor - The Editor instance that triggered the event
    2. id - ID of the newly created row
    3. values - The values submitted by the client-side
    4. $row - The newly created row's data, as read from the database

Edit

  • preEdit (cancellable) - Triggered prior to updating an existing row and before validation has occurred
    1. editor - The Editor instance that triggered the event
    2. id - ID of the row to be edited
    3. values - The values submitted by the client-side
  • validatedEdit - Triggered immediately prior to updating an existing row, after validation has occurred (since 1.9.3)
    1. editor - The Editor instance that triggered the event
    2. id - ID of the row to be edited
    3. values - The values submitted by the client-side
  • writeEdit - Data has been written to the database, but not yet read back, allowing the database to be updated before the data is gathered to display in the table
    1. editor - The Editor instance that triggered the event
    2. id - ID of the row to be edited
    3. values - The values submitted by the client-side
  • postEdit - Triggered immediately after an existing row has been updated
    1. editor - The Editor instance that triggered the event
    2. id - ID of the row that has been edited
    3. values - The values submitted by the client-side
    4. $row - The updated row's data, as read from the database

Remove

  • preRemove (cancellable) - Triggered immediately prior to deleting an existing row
    1. editor - The Editor instance that triggered the event
    2. id - ID of the row to be deleted
    3. values - The values submitted by the client-side (i.e. the row's data set)
  • postRemove - Triggered immediately after a row has been deleted
    1. editor - The Editor instance that triggered the event
    2. id - ID of the row that has been deleted
    3. values - The values submitted by the client-side (i.e. the row's data set)

Upload

  • preUpload (cancellable) - Triggered immediately prior to a file upload being processed
    1. editor - The Editor instance that triggered the event
    2. data - Data submitted by the upload form
  • postUpload - Triggered after a file has been uploaded and information about it read from the database
    1. editor - The Editor instance that triggered the event
    2. id - ID of the database record for the uploaded file (or the file's unique name if a database record is not used)
    3. files - The file information that has been read from the database
    4. data - Data submitted by the upload form

Please note that for multi-row creation, editing and deletion, the events are triggered once for each row.

Cancellable events

The pre* events are all cancellable, allowing the server-side process to optionally decide if a row should be processed or not. This can be useful as a form of data validation, disallowing users from certain actions (although please note that this is not a replacement for validation - no error will be shown to the end user if the processing of a row is cancelled!).

To cancel the processing of a row return false from the event handler. Any other rows that were also submitted, which are not cancelled themselves, will be correctly processed and the client-side table appropriately updated.

Examples

Modifying fields

It is quite common to wish to store information in the database that is not directly settable by the end user, and furthermore, to have different information stored based on the action that has been triggered from the client-side. This can easily be achieved with events and the methods of the Field class.

Consider the case where we have information about the user who is using the session available in a session variable (req.session.user_id). We wish to store in the database this information for who created the entry and who last updated the item.

This can be achieved using the preCreate and preEdit methods:

Controller:

router.all('/api/staff', async function(req, res) {
    let editor = new Editor(db, 'staff')
        .fields(
            new Field( 'first_name' ),
            new Field( 'last_name' ),
            new Field( 'position' ),
            new Field( 'email' ),
            new Field( 'created_by' ).set( Field.SetType.Create ),
            new Field( 'last_updated' )
        )
        .on( 'preCreate', (editor, values) => {
            editor
                .field( 'created_by' )
                .setValue( req.session.user_id );
        } )
        .on( 'preEdit', (editor, id, values) => {
            editor
                .field( 'last_updated' )
                .setValue( new Date().toISOString() );
        } );

    await editor.process(req.body);
    res.json(editor.data());
});
  • Line 1 - Express router for the /api/staff URL (you don't need to use Express, use anything you want!)
  • Lines 2-8 - Simple Editor initialisation with six fields. Note that created_by is configured to be writeable only for a create action.
  • Line 9 - Listen for the preCreate event
  • Line 10 - Get the created_by field to modify it
  • Line 11 - Set the field so that it will be written only on the create action
  • Line 12 - Set the value to write to the database to be the session variable of interest.
  • Line 14 - Listen for the preEdit event (note it has different parameters to preCreate)
  • Lines 15-17 - Set the last_updated value to the current time on edit.

Logging changes

As a further example of how to use the events emitted by Editor, consider the case where we want to log information to a database table that details what user made a change, what the change was and when. For this we can use use either the pre* or post* events, but we will use the post* events here which ensures that data is logged only if it was successfully inserted into the database.

Consider the following code:

function logChange( action, id, values, session ) {
    db.insert( 'staff-log', {
        user: session.user_id,
        action: action,
        values: JSON.stringify( values ),
        row: id,
        when: new Date().toISOString()
    } );
}

router.all('/api/staff', async function(req, res) {
    let editor = new Editor(db, 'staff')
        .fields(
            new Field( 'first_name' ),
            new Field( 'last_name' ),
            new Field( 'position' ),
            new Field( 'email' )
        )
        .on( 'postCreate', (editor, id, values, row) => {
            logChange( 'create', id, values, req.session ); 
        } )
        .on( 'postEdit', (editor, id, values, row) => {
            logChange( 'edit', id, values, req.session ); 
        } )
        .on( 'postRemove', (editor, id, values) => {
            logChange( 'delete', id, values, req.session ); 
        } )

    await editor.process(req.body);
    res.json(editor.data());
});
  • Lines 1-9 - logChange function which will insert a row into the logging table using the Knex.JS insert method.
  • Line 11 - Express router. Again, any router could be used, Express is used for convenience here.
  • Lines 19-25 - Attach event listeners to postCreate, postEdit and postRemove which will call logChange with suitable arguments.

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.