porno porno rokettube
Page 1 of 2 12 LastLast
Results 1 to 10 of 17

Thread: Grails, jQuery & the jQuery Grid - Part Four

  1. #1
    Administrator dave's Avatar
    Join Date
    Mar 2010
    Location
    West Yorkshire, UK - Valencia Spain
    Posts
    110

    Post Grails, jQuery & the jQuery Grid - Part Four

    The fourth installment of my Grails & jQuery grid tutorial is to cover adding, editing and deleting data.

    I also want to spend a little time tweaking the interface to take advantage of some of the core jQuery functionality to improve the user experience.

    1. Adding Data

    The jQuery grid already has a built-in system that provides us with a popup form based UI for adding new records. All we need to do is change our grid definition to enable it and let it know we want to provide the user with the ability to add.

    To accomplish this we can use the 'navgrid' method which allows us to add buttons to perform adding/editing/deleting, searching and refreshing of the grid.

    The navgrid method takes several sets of options for controlling which buttons to show, and individual options for adding/editing and deleting as shown in the code below.

    Add the navGrid method to your jqGrid definition so your whole call to jqGrid looks as below.

    Code:
    jQuery("#customer_list").jqGrid({
          url:'jq_customer_list',
          datatype: "json",
          colNames:['First Name','Last Name','Age','Email Address','id'],
          colModel:[
            {name:'firstName'},
            {name:'lastName'},
            {name:'age'},
            {name:'emailAddress'},
            {name:'id',hidden:true}
          ],
          rowNum:2,
          rowList:[1,2,3,4],
          pager:'#customer_list_pager',
          viewrecords: true,
          gridview: true
        }).navGrid('#customer_list_pager',
            {add:true,edit:false,del:false,search:false,refresh:false}, // which buttons to show?
            {},         // edit options
            {addCaption:'Create New Customer'},  // add options
            {}          // delete options
        );
    By default when you use the navGrid, buttons are set to appear by default, so I have indicated all buttons are disabled except for the add button.
    I have also indicated that the add dialog has a custom caption of 'Create New Customer'.

    If you run the tutorial now, you will see the Add button appear in the pager area marked with a image of a addbutton..jpeg. Alternative images can be specified in the options but that is beyond the scope of this tutorial.



    By clicking the add button, you will see the dialog appear as below, but there is a obvious issue in that no fields are present!



    We need to now instruct the grid that fields in our column model should be used when modifying/adding data. This is accomplished by adding editable:true to each set of column options, e.g.

    Code:
    {name:'firstName', editable:true}
    Mark each field as editable except for the id column and re-run your application to see the new add dialog.



    That's better but the age column certainly doesn't need to be that wide, thankfully when a column is marked as being editable, we can also supply edit options which will let us change the width.

    Change the age colmodel entry to include a size option:

    Code:
     {name:'age',
      editable:true,
      editoptions:{size:3}
     },
    I will also increase the size of the email to 30.

    Running the application again we will see the age field in the dialog has been resized accordingly.

    We can also add a few rules to apply some basic validation before the data is submitted by making use of editrules. In this case I will indicate that all fields are required, that the age field should be an integer and that the email address should be a valid email.

    The entire colModel section now should be:

    Code:
    colModel:[
        {name:'firstName',
         editable:true,
         editrules:{required:true}
        },
        {name:'lastName',
         editable:true,
         editrules:{required:true}
        },
        {name:'age',
          editable:true,
          editoptions:{size:3},
          editrules:{required:true,integer:true}
        },
        {name:'emailAddress',
         editable:true,
         editoptions:{size:30},
         editrules:{required:true,email:true}
        },
        {name:'id',hidden:true}
    ],
    And if you run the application now, you can test out the validation rules, this example show an incorrect value in the age field:

    So far, so good, we can validate the data before sending to the server, but we still need to add to our controller a method which will process the data sent and persist it. In our grid definition we define the url to retrieve data as 'jq_customer_list', an appropriate name for the edit/action would be jq_edit_customer so add that as the 'editurl' property underneath the 'url' property in the grid definition so you will now have:

    Code:
    url:'jq_customer_list',
    editurl:'jq_edit_customer',
    and in the controller, create the corresponding new method as below.
    Code:
    def jq_edit_customer = {
        
    }
    Note we will need to interrogate the request parameters to determine the data AND the operation we want to perform, i.e. Add. To see all the parameters the grid sends, see what is output in the server log when you place a 'println params' statement in our method and try adding a new record. You should see something like

    Code:
    [id:_empty, lastName:Bloggs, email:joe@dbws.net, oper:add, age:10, firstName:Joe, action:jq_edit_customer, controller:customer]
    This single method will be used for multiple functions, Adding, Editing and Deleting hence the requirement of the 'oper' parameter.

    So a basic method that will fulfill the task of adding data would be:

    Code:
    def jq_edit_customer = {
          def customer = null
    
          // determine our action
          switch (params.oper) {
            case 'add':
              // add instruction sent
              customer = new Customer(params)
              if (customer.hasErrors() || ! customer.save())
                customer = null
              
              break;
          }
    
          // return our customer object as JSON
          render customer as JSON
        }
    This simply firstly checks the operation we want to perform, if it is an ADD operation then create a new customer object based on the parameters sent, persist it and return the object as a JSON representation.

    This works fine, but needs some necessary adjustments. If you run the application with just the above changes, You may not see the data being added to the table unless you keep a close eye on the number of records. There is also no status of the operation being passed back to the user so we really need to let the user know of the result of the add operation.

    What we can do to gain more control is hook into the 'afterSubmit' event. We can add our own function that fires after the submit, and interprets the server response. As we're taking over the afterSubmit event we can change the controller to return whatever we want as long as we interpret the response in the event.

    Firstly though, I want to create a 'DIV' placeholder for us to let the user know any 'success' messages we have. This will go on the main page, any 'errors' I want to be displayed within the add dialog itself.

    Add a div placeholder to list.gsp just under the Customer List H1 heading as below;

    Code:
    <div id='message' class="message" style="display:none;"></div>
    Note: We predefine the style display:none so it will only be shown when we need it to.

    Change the add/edit controller method to the following:

    Code:
    def jq_edit_customer = {
          def customer = null
          def message = ""
          def state = "FAIL"
          def id
    
          // determine our action
          switch (params.oper) {
            case 'add':
              // add instruction sent
              customer = new Customer(params)
              if (! customer.hasErrors() && customer.save()) {
                message = "Customer  ${customer.firstName} ${customer.lastName} Added"
                id = customer.id
                state = "OK"
              } else {
                message = "Could Not Save Customer"
              }
    
              break;
          }
    
          def response = [message:message,state:state,id:id]
    
          render response as JSON
        }
    Now instead of passing back the customer object as JSON, we are sending a message, the state (either 'FAIL' or 'OK') and the id of the customer if it's new.

    Change your 'addOptions' definition to include the new afterSubmit event we're about to add:

    Code:
     {addCaption:'Create New Customer',
      afterSubmit:afterSubmitEvent},  // add options
    Now add the afterSubmitEvent code, (add this function just above the ending </script> tag) :

    Code:
     function afterSubmitEvent(response, postdata) {
            var success = true;
        
            var json = eval('(' + response.responseText + ')');
            var message = json.message;
        
            if(json.state == 'FAIL') {
                success = false;
            } else {
              $('#message').html(message);
              $('#message').show().fadeOut(10000);
            }
            
            var new_id = json.id
            return [success,message,new_id];
        }
    In this function we now interpret the JSON response. If it is a failure, we set success to false. This will trigger the dialog to display the contents of the message variable in the dialog.

    If it's not FAIL, then we use a quick jQuery snippet to place the message text in our 'DIV' placeholder, then set it visible with .show(), and then fade it out after 10 seconds.



    You will have noticed the dialog stays open after we've added a new record, this behaviour is optional and can be turned off by setting the option 'closeAfterAdd' to true.

    By leaving the dialog open we enable to the user to enter data faster into the system than by closing it and having the user click the add button each time. An alternative would be to have an input form constantly available on the main page.

    Another basic UI improvment for the user would be to enable the dialog to submit data when the user presses the enter key, this is always a good idea so the user doesn't have to reach for the mouse after each record is entered just to click submit.

    This is accomplished by setting the option 'savekey' to [true,13]. The true represents we want to enable the feature and the 13 represents the ASCII key code, i.e. Enter.


    2. Editing Data

    The method I want to describe for editing data closely follows the steps we have already taken for adding new records via the popup dialog.

    An alternative to using the dialog form of data modification is to use inline editing. This means we can edit directly the data on the rows in the grid, or even further just allow cell editing.

    I will create a seperate tutorial that should be considered as optional to this series to show how you can use inline editing with grails and the grid.

    Firstly enable editing by setting the edit property to true in the navGrid call :

    Code:
    {add:true,edit:true,del:false,search:false,refresh:true},
    This will provide you with the edit button on the grid toolbar edit button..jpeg
    You will already be able to select a row, and click the edit button and see the popup dialog displayed with the data presented.

    I want to also indicate that the dialog should be closed after submitting data, when editing, this we do with the closeAfterEdit parameter.

    I also want the edit dialog to use the same callback event after submitting that the add dialog used, so also set the afterSubmit property in the edit options, so the entire edit options set looks like:

    Code:
    {closeAfterEdit:true,
         afterSubmit:afterSubmitEvent
        },
    All we need to do to complete the functionality in the dialog is to ensure our controller will respond when we submit the data, so we must add functionality for when the 'oper' param is 'edit'

    Add the following case block to the switch statement to respond to an 'edit' request:

    We can either setup a case condition specifically for 'edit', or just add code to the 'default' switch condition. I highlight this now, as if you decide to also use inline editing, when the request is made to the grids edit url, inline edits do not also supply a 'oper' parameter, so you would need to use the default switch condition.

    So in short, either start the next block with case 'edit': for extra code clarity or case default: if you may also use inline editing.

    Code:
     case 'edit':
      // edit action
      // first retrieve the customer by its ID
      customer = Customer.get(params.id)
      if (customer) {
        // set the properties according to passed in parameters
        customer.properties = params
        if (! customer.hasErrors() && customer.save()) {
          message = "Customer  ${customer.firstName} ${customer.lastName} Updated"
          id = customer.id
          state = "OK"
        } else {
          message = "Could Not Update Customer"
        }
      }
      break;
    That's all we need to do, running now you should be able to edit each record and see a notification claiming the update was successful. Notice how the grid also updates automatically upon submit.

    3. Deleting Data

    The changes we now have to make to allow the user to delete records is very minimal as we are building on our existing code.

    Firstly, we need to enable the Delete button. Change the navgrid options, to enable the 'del' property:

    Code:
    add:true,edit:true,del:true,search:false,refresh:true
    We also want to let the user know if the deletion was successful so we should again hook into the afterSubmit event by adding afterSubmit:afterSubmitEvent to the delete options.

    And finally we just need to add the necessary controller additions:

    Code:
    case 'del':
      // check customer exists
      customer = Customer.get(params.id)
      if (customer) {
        // delete customer
        customer.delete()
        message = "Customer  ${customer.firstName} ${customer.lastName} Deleted"
        state = "OK"
      }
      break;
    When you delete a customer now, you should be seeing the confirmation dialog, and when you confirm the deletion, you should also see the fading message above the grid.

    Miscellaneous Tweaks

    I personally prefer NOT to use the grid's own toolbar and present the user with full buttons that perform the add,edit and delete functions.

    To accomplish this first define your button area, in this case place this div underneath the div tag for the customer_list_pager:

    Code:
    <div style="margin-top:5px">
      <input class="ui-corner-all" id="btnAdd" type="button" value="Add Record"/>
      <input class="ui-corner-all" id="btnEdit" type="button" value="Edit Selected Record"/>
      <input class="ui-corner-all" id="btnDelete" type="button" value="Delete Selected Record"/>
    </div>
    Now just to wire up the buttons to the grid functionality, add the following immediately after your $(document).ready(function () { line

    Code:
    // set on click events for non toolbar buttons
                    $("#btnAdd").click(function(){
                      $("#customer_list").jqGrid("editGridRow","new",
                         {addCaption:'Create New Customer',
                         afterSubmit:afterSubmitEvent,
                         savekey:[true,13]});
                    });
    
                    $("#btnEdit").click(function(){
                       var gr = $("#customer_list").jqGrid('getGridParam','selrow');
                       if( gr != null )
                         $("#customer_list").jqGrid('editGridRow',gr,
                         {closeAfterEdit:true,
                          afterSubmit:afterSubmitEvent
                         });
                       else
                         alert("Please Select Row");
                    });
    
                    $("#btnDelete").click(function(){
                      var gr = $("#customer_list").jqGrid('getGridParam','selrow');
                      if( gr != null )
                        $("#customer_list").jqGrid('delGridRow',gr,
                         {afterSubmit:afterSubmitEvent});
                      else
                        alert("Please Select Row to delete!");
                    });
    That will now give you 3 new functioning buttons underneath your main table:



    That concludes the basic form based editing section of this tutorial. As mentioned I will create a separate tutorial for those interested in using inline cell or row editing.



    A full set of edit options can be viewed here : http://www.trirand.com/jqgridwiki/do...ing_properties
    Attached Files Attached Files

  2. #2
    Junior Member
    Join Date
    Jun 2010
    Posts
    1
    Great tutorial!
    Looking forward to inline row a and cell editing!

  3. #3
    Junior Member
    Join Date
    Aug 2010
    Posts
    1
    wow. nice tutorial.
    in my example email address not saved.
    so i changed col name to emailAddress instead use index property.

  4. #4
    Junior Member
    Join Date
    Sep 2010
    Posts
    1
    Very nice. This works as advertised. I'd like to find an equivalent for jsTree. If none exists, perhaps I'll write one. I'm inspired by your work, you see.

  5. #5
    Administrator dave's Avatar
    Join Date
    Mar 2010
    Location
    West Yorkshire, UK - Valencia Spain
    Posts
    110
    Thanks, I do want to expand the set of tutorials, haven't quite decided what next, as doing a fair bit of Android development at the moment, the Grails work is on a lower priority but depending what seems to be in demand I'll try and find time to add some more. I noticed someone was asking how to do Ajax Master/Detail pages on nabble, that would be a very quick addition so that will probably come next.



    Quote Originally Posted by jnorman67 View Post
    Very nice. This works as advertised. I'd like to find an equivalent for jsTree. If none exists, perhaps I'll write one. I'm inspired by your work, you see.

  6. #6
    Junior Member
    Join Date
    Sep 2010
    Posts
    1

    inline cell or row editing

    Did you ever add the separate inline cell or row editing example?

    Thanks for the tutorial, it was great!

  7. #7
    Administrator dave's Avatar
    Join Date
    Mar 2010
    Location
    West Yorkshire, UK - Valencia Spain
    Posts
    110
    I can certainly make that the focus of my next one.

  8. #8
    Junior Member
    Join Date
    Oct 2010
    Posts
    1
    Thanks a lot for the tutorial! It helped a lot! But it appears that when I try to edit a row or add a new row, the popup window does not close after entering the details and clicking on submit. I had to click on "cancel" and then reload the grid either by refreshing the page or by clicking on the reload icon on the bottom of the grid. Is there a way around this? Would appreciate a lot if this can be resolved. Thanks a lot in advance!

  9. #9
    Administrator dave's Avatar
    Join Date
    Mar 2010
    Location
    West Yorkshire, UK - Valencia Spain
    Posts
    110
    Quote Originally Posted by Kamaraj View Post
    Thanks a lot for the tutorial! It helped a lot! But it appears that when I try to edit a row or add a new row, the popup window does not close after entering the details and clicking on submit. I had to click on "cancel" and then reload the grid either by refreshing the page or by clicking on the reload icon on the bottom of the grid. Is there a way around this? Would appreciate a lot if this can be resolved. Thanks a lot in advance!
    Check your code/grid definition for the presence of 'closeAfterEdit' , e.g.

    Code:
    $("#btnEdit").click(function(){
                       var gr = $("#customer_list").jqGrid('getGridParam','selrow');
                       if( gr != null )
                         $("#customer_list").jqGrid('editGridRow',gr,
                         {closeAfterEdit:true,
                          afterSubmit:afterSubmitEvent
                         });
                       else
                         alert("Please Select Row");
                    });
    if thats present it should automatically close the popup dialog after clicking submit.

  10. #10
    Junior Member
    Join Date
    Jun 2011
    Posts
    1

    jqGrid Inline edit

    I am doing inline edit for jqGrid, I am not able to post the data on the server , I can edit the grid but changes dont not reflect in the database also when I refresh the grid all the changes I made goes away, I had been trying to make it work, but no luck, I would appreciate your help

    here is the code I am trying to make it work



    afterEditCell: function(rowid, cellname, value, irow, icol) {
    if (window.pageXOffset) {window.pageXOffset = scrollPosition;};
    if (document.body.parentElement) {document.body.parentElement.scrollLeft = scrollPosition;};
    if (document.body) {document.body.scrollLeft = scrollPosition
    }
    jQuery("#grid_list").jqGrid('saveRow',rowid, false)
    },

    onSelectCell: function(id){
    if(id && id!==lastsel){
    // jQuery('#grid_list').jqGrid('restoreRow',lastsel);
    jQuery('#grid_list').jqGrid('editRow',id, true);
    jQuery("#grid_list").jqGrid('saveRow',id, false);
    lastsel=id;
    }
    var cont = $('#grid_list').getCell(id, 'MyCol');
    var val = getCellValue(cont);
    },

    gridComplete: function(){
    var ids = jQuery("#grid_list").jqGrid('getDataIDs');
    for(var i=0;i < ids.length;i++){
    jQuery("#grid_list").jqGrid('saveRow',ids[i], false)
    jQuery("#grid_list").jqGrid('setRowData', ids[i], false);
    }
    },

    pager: jQuery("#grid_list_pager"),
    viewrecords: true,
    gridview: true,
    height: 500,
    // forceFit: true,
    cellEdit:true,
    caption: "All_Defects",
    cellurl : 'jq_defect_edit',
    cellsubmit: 'remote',
    multiselect: false,



    }).navGrid('#grid_list_pager',
    {add:true,edit:true,del:true,search:false,refresh: true}, // which buttons to show?
    {closeAfterEdit:true,
    afterSubmit:afterSubmitEvent
    }, // edit options
    {addCaption:'Create New defect',
    afterSubmit:afterSubmitEvent,
    savekey:[true,13]}, // add options
    {afterSubmit:afterSubmitEvent} // delete options
    );
    });


    function afterSubmitEvent(response, postdata) {
    var success = true;

    var json = eval('(' + response.responseText + ')');
    var message = json.message;

    if(json.state == 'FAIL') {
    success = false;
    } else {
    $('#message').html(message);
    $('#message').show().fadeOut(10000);
    }

    var new_id = json.id
    return [success,message,new_id];
    }


    </script>
    </div>
    </body>
    </html>

Page 1 of 2 12 LastLast

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Forum Design by Tucanoo Solutions Ltd Grails Development Specialists.