Wednesday, January 23, 2013

Inline editable fields for an HTML table

I am a fan of Twitter's Bootstrap. It is simply fantastic. But you can make it more powerful if you use jQuery plugins and Bootstrap extensions. So here is Bootsnipp - a site that lists cool Bootstrap extensions.
Traditionally on the web, when you want to capture information from the user you have to create a form. This is great, but sometimes building a form is not that natural. Sometimes we want to edit a value in the middle of a text, or edit the value from a table. There are a lot of solutions out there, and this is just one of them using Bootstrap and a neat extension named X-editable.
While the X-editable site shows a lot of examples, I could not find a way to make my table handle more like a form. What this means is that I want to edit the fields in the table without posting the changes and have a "Save" and "Reset" buttons to apply the changes or revert to the original values.
The "Save" button is nicely demo-ed on X-editable site but the reset functionality was not to my liking as the example is not truly reverting the values to their original state, but instead it is setting them to null (which is fine for that example as it deals with creating a new entry).
Then I realized that the library does not save the original value and it is lost. So I plugged in my handlers for save and reset in order to add my desired functionality.The trick is that I save the original value in the element itself on the "save" event and then make sure I clean it up when the processing completes (either successfully or the reset is invoked). My example also extends the original example and looks for next editable item on the rows as well as columns.
// this is to automatically make the next item in the table editable
$('.edit').on('save', function(e, params){
    var that = this;
    // persist the old value in the element to be restored when clicking reset
    var oldItemValue = $(that)[0].innerHTML;
    if (!$(that).attr('oldValue')) {
     $(that).attr('oldValue', oldItemValue);
    }
    setTimeout(function() {
        // first search the row
        var item = $(that).closest('td').next().find('.edit');
        console.log(item);
        if (item.length == 0) {
            // check the next row
            item = $(that).closest('tr').next().find('.edit');
        }
        item.editable('show');
    }, 200);
});
The "Reset" button handler:
$('#resetbtn').click(function() {
    $('.edit').each(function() {
        var o = $(this);
        o.editable('setValue', o.attr('oldValue')) //clear values
         .editable('option', 'pk', o.attr('pk')) //clear pk
         .removeClass('editable-unsaved')
      .removeAttr('oldValue');
    });
});
And the "Save" button handler:
$('#savebtn').click(function() {
   $('.edit').editable('submit', { 
       url: '/post', 
       //ajaxOptions: { dataType: 'json' },           
       success: function(data, config) {
           $(this).removeClass('editable-unsaved') //remove unsaved class
               .removeAttr('oldValue'); // clear oldValue
       },
       error: function(errors) {
           console.log('error');
           var msg = '';
           if(errors && errors.responseText) { //ajax error, errors = xhr object
               msg = errors.responseText;
           } else { //validation error (client-side or server-side)
               $.each(errors, function(k, v) { msg += k+": "+v+"
"; });
           } 
       }
   });
});
You can find the code and a demo here.

No comments: