Friday 30th June, 2017

Always visible editing panel

When you are working with a software library, you want it to fit into your site and design - not have it force you to its way of thinking. This philosophy is deeply engrained into both DataTables and Editor, as shown by their ability to be styled by various popular CSS frameworks. Editor in particular is designed from the ground up to be flexible and fit into your applications.

The default mode of editing a form in Editor is with a modal window (also sometime referred to as a lightbox). This can be a useful interface paradigm for the end user as it provides separation between the data access and data writing - it quite literally looks like different layers. The downside is that because the form overlays the rest of the page you can loose the context of the data you are editing. This isn't always an issue, but in complex applications it can be useful for the user to refer to other data points when editing a row.

To that end, one common question for Editor is, if it has the ability to show its form in a dedicated area on the page, not in a modal, but rather alongside other content. Absolutely, this is possible! An example is shown below. In this post I'll describe how this example was put together.

Example

Name Salary
Name Salary

Select a row
to edit or delete

Or add a new row

This example shows a DataTable with just two columns and an input area to the right of it. The table is shown with only two columns due to the horizontal width constraints of this blog post, but in a real application a table of any size could be used. The space is equally split between the table and the form area.

Clicking on a row you will be able to see that the data for the row is instantly shown in the form in an editable state. There are buttons to save any changes and also to delete the row. When the row is deselected the original content for the form area is shown again, along with a link to enter data for a new row which will show the create form in that location.

To see the full Javascript and CSS used for these examples (note they include some small customisations to be suitable for this display) see:

Display controllers

Although Editor's default display is to show the form in a model, it is actually very easy to tell it to display the form somewhere else. The code that controls where the form is shown is termed a display controller in Editor. It has three functions to perform:

  • Initialisation - An Editor instance is being created, and tells the display controller that it will be used for that Editor.
  • Display the form - When Editor wants to display the form, it will tell the display controller and pass it in an element that contains the form.
  • Hide the form - Once the editing is complete or the form otherwise dismissed, Editor will ask the display controller to dismiss the form.

With these three simple actions, you can display an Editor form anywhere you wish; another element as shown here, a Bootstrap modal, a child row or even a new window if you so wished.

Initialisation

The initialisation of this plug-in is possibly the most interesting part of this code. We need to consider the case where there are multiple Editor's on the page and each will be displaying its own form in a different container element. Thus, rather than simply having a static display controller name as described in the manual, we will have a function that we can pass in the element where we want the form to display and it will generate a random name which can be used for Editor's displayController property. This makes use of Javascripts ability to use closures - i.e. retaining a value from the enclosing function.

function onPageDisplay ( elm ) {
    var name = 'onPage'+Math.random();
    var Editor = $.fn.dataTable.Editor;
    var emptyInfo;

    Editor.display[name] = $.extend( true, {}, Editor.models.display, {
        init: function ( editor ) {
            emptyInfo = elm.html();
            return Editor.display[name];
        }
    } );

    return name;
}

Note that the function will create a display controller plug-in in the standard fashion (attaching it to $.fn.dataTable.Editor.display) with the standard properties required for the plug-in. Above the init function is shown - open and close are below.

The only initialisation required here is to make sure that we have a copy of the HTML that already exists in the form display area. This is so it can be reinstated when a row is deselected.

Displaying the form

Displaying the form is trivial in the open function. We simply remove anything present (note the use of $().detach() which will preserve event handlers assigned to elements in the container) and attach the form Editor has built. If there is a callback function, it should be called when the form is ready (this is useful for animations, etc):

// Show the form
open: function ( editor, form, callback ) {
    elm.children().detach();
    elm.append( form );

    if ( callback ) {
        callback();
    }
},

Hiding the form

To hide the form (i.e. in this example when a row is deselected) its as trivial as the open case - just remove the contents and then insert the original content. Again, if there is a callback, trigger it.

// Hide the form
close: function ( editor, callback ) {
    elm.children().detach();
    elm.html( emptyInfo );

    if ( callback ) {
        callback();
    }
}

Complete plug-in code

Although the above shows all the code required for this display controller plug-in, it does need assembly. To see the completed plug-in with usable code, please refer to this page.

Event handling

We could now use the standard editing buttons that are shown in the majority of the Editor examples - i.e. Add, Edit and Delete shown above the table and call it done. It would work, but it wouldn't really fit with the idea of having the form instantly accessible.

Instead, what we'll do is have the form display when a row in the table is selected.

Triggering an edit

When a row is selected in the DataTable (via the Select extension) the select event is triggered - at this point we want to call edit() on the selected rows (use rows().indexes() to get all of the selected rows, not just the latest one, which allows for multi-row editing). Likewise, when a row is deselected, we would want to call close():

table
    .on( 'select', function () {
        var indexes = table.rows({selected:true}).indexes();

        editor.edit( indexes, {
            title: 'Edit row'
        } );
    } )
    .on( 'deselect', function () {
        editor.close();
    } );

Deleting a row

When a row is selected, for this example we want to have the form show not only the row in an editing state with a save button, but also a delete button so the row can be removed from the table. We can do that through the buttons parameter of the form-options object passed to edit() (e.g. the object where the title parameter is used above). This in turn makes use of the buttons() method.

Its almost easier to understand this from the code than the text - take a look at the code below which defines two buttons - the first is just text so it does the standard Editor action of saving the form (e.g. submit()). The second button has a function (fn) which will be called when the button is activated. In this case it called remove() to set-up the delete action and then submits it immediately:

buttons: [
    'Save changes',
    {
        label: 'Delete',
        fn: function () {
            editor
                .remove( indexes, false )
                .submit();
        }
    }
]

Creating a new row

The only thing left is to do is provide a way to create a new row. For this we just use a standard jQuery click event listener on the text we put into the page for the new row, and call the create() method.

In the code below again the buttons parameter is used, in this case to add a cancel button in addition to the save button.

$('#form-container').on( 'click', 'p.add-new', function (e) {
    e.preventDefault();

    editor.create( {
            title: 'Create new row',
            buttons: [
                'Save',
                {
                    label: 'Cancel',
                    fn: function () {
                        editor.close();
                    }
                }
            ]
    } );
} );

Customise away!

Both Editor and DataTables are designed to be easy to get up and running with as quickly as possible. After all, the whole point of library software is to save you development time so you can get on with other things! But you don't need to just use the default options - they should, and can, fit into your application as you need them to.

With the use of the API and some basic Javascript, you can customise these libraries to suit your needs.