Friday 25th July, 2014

Duplicate buttons in Editor

Editor provides built in support for the three basic buttons needed in an editable DataTable: Create, Edit and Delete. One further action that is particularly useful is the ability to create a new record using the values from an existing row in the table as the default values - i.e. a duplicate button. This can facilitate fast data entry when working with data that has common information; for example entering information from a monthly invoice into a payments database or tracking a team's score through season.

Although there isn't a built in duplicate button type in Editor, this blog post will show how that functionality can be performed very easily with the Editor API, using a TableTools button to provide the user interaction and finally creating a reusable button plug-in for TableTools that can be used in any of your tables with the addition of a single line of code.

The results of the information presented in this post can be see in the duplicate button example on the Editor site.

Duplicate action

Creating the code that actually creates the duplicate entry is actually very easy with the Editor API and involves a simple two step operation:

  1. Place the row to be used as the basis for the new entry into edit mode (using edit(). This has the effect of setting the fields to the values of the row in question. We just hide the edit form from the user (passing the second parameter to edit() as false) and then read all of the values back from the form using val().
  2. Now show a create form and populate the field values with the values read from step one - this can be done with the create() and set() methods.
var values = editor.edit( row, false ).val();

editor
    .create( {
        title: 'Duplicate',
        buttons: 'Create from existing'
    } )
    .set( values );

where:

  • editor is the Editor instance to be used
  • row is the tr element that will have its data used as the basis for the new record

It would be possible to read the data from the row directly (row().data()), and skip step 1, but the addition of that step allows complex / nested JSON data to be used, such as that on a join table. Additionally it ensures that the few simple lines above are completely reusable for any Editor form.

Note that because this is all being done with the Editor API you could perform additional tasks such as submitting the new record automatically without requiring user input, or setting fields to have a different value than that of the original (this might be useful if there is a "created" field).

TableTools button

Now that we have the basic duplication code, let's create a button for the user to trigger the duplicate action. You could use any event handler you wish to trigger this action (a key press, click on a link, etc), but in keeping with the three standard TableTools create, edit and delete buttons of Editor, here we will create a new Duplicate button.

When creating a DataTable with the TableTools buttons, the tableTools option is passed in with an array of button descriptions (aButtons). For Editor, this will typically look something like:

tableTools: {
    sRowSelect: "os",
    aButtons: [
        { sExtends: "editor_create", editor: editor },
        { sExtends: "editor_edit",   editor: editor },
        { sExtends: "editor_remove", editor: editor }
    ]
}

We are not restricted to just those three buttons - as many as required can be added, defining whatever actions you require. The action taken on activation of the button is controlled by the fnClick property and we can use existing buttons as the basis for our new button through the sExtends option.

Its a bit of a mouthful all of that, but it boils down fairly simply to adding the code below to the aButtons array:

{
    sExtends:    "select_single",
    sButtonText: "Duplicate",
    fnClick:     function( button, conf ) {
        var node = this.fnGetSelected();

        if ( node.length !== 1 ) {
            return;
        }

        // ... perform duplicate action ...
    }
}

Here we extend the select_single button type (it is enabled only when a single row is selected), set the button text to Duplicate and prepare an fnClick function. In the fnClick we use TableTools' fnGetSelected API method to get the node of the selected row (our row variable from the duplicate code above). All that remains now is to drop the code from above into the function!

You can see this code running live in the Editor duplicate button example on the Editor site.

TableTools extension

The final task is to create a reusable TableTools button that can be used as easily as the built in Editor button types. This is done by adding our new button type to the $.fn.dataTable.TableTools.buttons object, extending an existing button to act as a template:

var buttons = $.fn.dataTable.TableTools.buttons;

buttons.editor_duplicate = $.extend( true, {}, buttons.select_single, {
    "sButtonText": 'Duplicate',
    "editor":      null,
    "fnClick":     function( button, conf ) {
        var node = this.fnGetSelected();

        if ( node.length !== 1 ) {
            return;
        }

        var values = conf.editor.edit( node[0], false ).val();

        conf.editor
            .create( {
                title: 'Duplicate',
                buttons: 'Create from existing'
            } )
            .set( values );
    }
} );

Note how the editor variable has been updated to be conf.editor - this is so we can set the editor property of the button when creating the button in the main script to have the button know which Editor instance to refer to.

Simply place the above code anywhere before your DataTables initialisation and then you will be able to create the buttons array like this (note the addition of the editor_duplicate type on the 6th line):

tableTools: {
    sRowSelect: "os",
    aButtons: [
        { sExtends: "editor_create",    editor: editor },
        { sExtends: "editor_edit",      editor: editor },
        { sExtends: "editor_duplicate", editor: editor },
        { sExtends: "editor_remove",    editor: editor }
    ]
}

Running example

As noted above, if you'd like to see this code running live, an example on the Editor site shows the duplicate button in action.