6

I am using the open source jqGrid plugin with EF4 and ASP.NET Web Forms. I need to set an input element in an inline-editable grid row based on a column value from the DB. For example, the first row could contain a DDL, the second row could contain a checkbox, etc.

I'm trying to achieve this using the custom_element and custom_values, like so:

$("#grid1").jqGrid({
    url: 'Default.aspx/getGridData',
    datatype: 'json',
    ...
    colModel: [
    ...
    //contains the input type ('select', etc.)
    { name: 'InputType', hidden:true }, 
    ...
    //may contain a string of select options ('<option>Option1</option>'...)
    { 
      name: 'Input', 
      editable:true, 
      edittype:'custom', 
      editoptions:{
         custom_element: /* want cell value from InputType column here */ , 
         custom_value:   /* want cell value from Input column here */ 
      } 
     }, 
    ...
    ]
});

The jqGrid docs say that I can call custom functions to set custom_element and custom_values, but I don't see how I can capture column values and pass them into my custom functions.

For setting custom_values, I did notice Oleg's nice solution using the list: parameter, but that appeared to involve an extra Ajax call. I want to avoid this, as I already have the all data I need from the initial Ajax call for the grid.

In summary, I need to do the following while in inline-edit mode:

  1. dynamically assign an input type from a DB value
  2. dynamically assign input values (for DDL or checkboxes) from a DB string

I am also open to skipping the use of custom_element and custom_values, but then I still face the same problem of dynamically setting the edittype and editoptions:{value:} parameters.

Any ideas on how to do this? Is there a different approach that I should be taking?

UPDATE: Thanks for your efforts to help me out. Per request, here is an abbreviated example of my JSON response:

{"d":[
{"Input":null,"InputType":"select"},
{"Input":"From downtown, proceed west on Interstate 70.", "InputType":"text"}
]}

With this data, I would want to show an empty select in one row, and a populated text field in the next row. Both would be editable inline.

SOLUTION: I have returned to this problem in order to find a solution that does not involve using custom_element and custom_values. Here is my solution (based on the accepted answer below) to changing edittype and editoptions :

loadComplete: function () {
    var rowIds = $("#grid1").jqGrid('getDataIDs');

    $.each(rowIds, function (i, row) {
       var rowData = $("#grid1").getRowData(row);

       if (rowData.InputType == 'select') {
          $("#grid1").jqGrid('restoreRow', row);
                var cm = $("#grid1").jqGrid('getColProp', 'Input');
                cm.edittype = 'select';
                cm.editoptions = { value: "1:A; 2:B; 3:C" };
                $("#grid1").jqGrid('editRow', row);
                cm.edittype = 'text';
                cm.editoptions = null;
       }
   });
}

Nota Bene: One important thing for me was remembering to set the editoptions back to null, after calling editrow. Also, as Oleg mentioned in the comments, avoiding the use of custom elements allows me to implement datepicker inputs without extra trouble. This was important for my app, so I ended up accepting Oleg's answer, but I still upvoted Walter's answer, as well. If this is bad form, I sincerely apologize. I simply wanted to reward the solution that worked best for me.

Community
  • 1
  • 1
bflow1
  • 969
  • 1
  • 10
  • 25
  • You wrote "I already have the all data I need from the initial Ajax call for the grid". Could you include an example of JSON data which you use? So that one sees in which format you send the information. – Oleg Sep 24 '11 at 09:48
  • @Oleg: Question updated to include JSON response. – bflow1 Sep 26 '11 at 16:35
  • Oleg's and Walker's answer were nearly equivalent to one another, in terms of usefulness. I accepted Walter's answer mainly because it was posted first. I should mention that I am very indebted to Oleg for his other jqGrid answers, and I will be generously upvoting those, once I get enough SO points. – bflow1 Sep 29 '11 at 20:45
  • It's a good idea to accept Walter's answer. Nevertheless I am perfectionist and I know that you can have some additional problems if you use custom editing. The main rule is: if you can find solution *without* custom editing you should not use it. After you read the `ElementType` value inside of `onSelectRow` handler you can just get column property with `var cm = grid.jqGrid('getColProp','FullName');` and change `cm.edittype` and `cm.editoptions` **before** call of `editRow`. In the way you will hold the most standard editing controls. – Oleg Sep 29 '11 at 21:11
  • 1
    Look at [the answer](http://stackoverflow.com/questions/6968507/how-to-clear-autocomplete-box-contents-in-add-form-after-adding-in-jqgrid/6969498#6969498) which describes problems with the usage of jQuery UI Autocomplete and custom editing. The custom controls will be placed in the `` having `id` and the `` which you created manually (see Walter's answer) has *no id*. So in the current implementation Autocomplete will not work. If you just use standard `edittype='text'` you can use Autocomplete or Datepicker for example without any additional work. – Oleg Sep 29 '11 at 21:17
  • @Oleg: You raise an excellent point about the element IDs. I need to check that out for all of the jqGrid-based grids that I have implemented. For the record, I preferred to completely avoid custom editing, but I was having trouble with the jqGrid 'loadcomplete' event. I didn't see that as a problem with your answer, but a problem with my jqGrid code. Now I would like to revisit your answer, since you have added some more information. – bflow1 Sep 29 '11 at 22:39
  • OK! If you would have additional questions - you are welcome! Which problems you have with the `loadComplete` event? – Oleg Sep 29 '11 at 22:47
  • @Oleg: I could not get the 'loadComplete' event to fire. I did not ask about that one, because it is a separate issue that has been answered at least once elsewhere on SO. However, I am much more concerned with this 'id' issue, because I haven't paid attention to how jqGrid generates 'id' for elements, such as in the case where you add a new row to the grid and fill in values. Perhaps it is worthy of a separate SO question, but first I need to carefully review your link shown above. Thanks very much for your feedback, sir! – bflow1 Sep 29 '11 at 23:07
  • If you use `datatype: 'json'` (and not `datatype` as function) the `loadComplete` will be called always if HTTP response has no errors. In case of error the `loadError` will be called. See [here](http://stackoverflow.com/questions/5500805/asp-net-mvc-2-0-implementation-of-searching-in-jqgrid/5501644#5501644) an example of the implementation of the `loadError` callback handler. – Oleg Sep 29 '11 at 23:19

2 Answers2

3

If you use incline editing you call editRow method somewhere directly in your code. Inside of the editRow method all options from the colModel, which are related to editing, will be examined and use. So you can change dynamically any options like editable, edittype or editoptions. The answer shows how one can change editable property. In the same way you can change any other properties.

If you want you can set the information about editing type and option inside of loadComplete event handle. It has data parameter which represent the original data sent from the server. So you can extend the data with and other information and set editable, edittype or editoptions for any columns based on the information.

Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • 1
    I have most of your suggestion working, but I cannot change the `edittype` of a **single row**. (I've seen lots of examples that change the `edittype` for **all** rows.) On `loadComplete`, I want to loop through the rows and change the `edittype` for each row to something else, such as `select`. I have updated my question to include my new `loadComplete`. Thanks, as always. – bflow1 Dec 28 '11 at 23:57
  • 1
    @bflow1: The `edittype` will be used only at the initialization time of the row editing. So one can change the `edittype` *before* one call `editRow` inside of `onSelectRow` for example. See [here](http://stackoverflow.com/a/4308172/315935) the demo. In case of form editing one can do the changes in the same way inside of `beforeInitData` for example. – Oleg Dec 29 '11 at 07:29
  • I am happy to report that your solution works for me, now. I can default all input fields to `edittype:text`, and then change the edittype for any input field in `loadcomplete`, **without resorting to custom editing**. (This was important because I do need to be able to use datepickers.) I'll post my solution above for reference. While mine is not that different from your link (and is of course based on yours), it does show a change to the `edittype`, instead of `edittype` parameter. Oleg, many thanks, as always. I'm upvoting your SO answers whenever I find them! – bflow1 Dec 29 '11 at 22:21
  • @bflow1: You are welcome! I am glad to read that you have working solution. Congratulation! Small remark to the code which you posted. You can save `$(this)` in a variable *at the beginning* of the `loadComplete`. You can use the variable later inside of internal function of the `loadComplete`. This can eliminate the usage of `$("#grid1")` and prepare the code be easy used with cut & paste in another grid. – Oleg Dec 29 '11 at 22:50
  • I appreciate the tip. In my actual production code, I am doing what you say. The code in my question is very much simplified from my production code, so it's easier for everyone to read the problem. I usually do this when I write a question. Thanks again! – bflow1 Dec 29 '11 at 23:14
2

Try this:

1. Define a handler for the grid's onSelectRow event (onSelectRow_handler) .
2. Inside the onSelectRow handler:
2.1. Set a globally scoped variable (lastRow) to the function's id parameter.
2.2. Call jqGrid's editRow() function to put the grid into edit-mode. This will trigger the function that you have defined as your custom_element renderer (myelem).
3. Inside myelem: call jqGrid's getRowData method to get the row data of the row you just selected for edit. From there you can get the value in the ElementType column and do your logic that decides which element to render.

You'll have to tweak my code a bit, as I didn't test it 100% end-to-end. I did verify that everything up to step 3 works. I didn't do any research into how you would code myvalue().

function renderGrid () {

    $("#grid").jqGrid({
        datatype: "local",
        colNames: ['Id', 'ElementType', 'Name' ],
        colModel: [
            { name: 'Id', index: 'Id', key: true, hidden: true },
            { name: 'ElementType', index: 'ElementType', },
            { name: 'FullName', index: 'FullName',
              editable: true, edittype: 'custom', 
              editoptions: { custom_element: myelem, custom_value: myvalue} }],
        viewrecords: true,
        caption: "",
        autowidth: true,
        height: 'auto',
        forceFit: true ,
        onSelectRow: onSelectRow_handler           
    });


}

var lastRow = null;
function onSelectRow_handler(id) {

    if(id && id!==lastRow){            
        lastRow=id;
    }
    // editRow will send grid into edit mode which will trigger
    $("#grid").editRow(id, true);

}

function myelem(value, options) {
    var data = $("#grid").getRowData(lastRow);
    // the elementType column contains a key to
    // indicate what Input Element to render
    var elementType = data.ElementType;

    if (elementType == 'text') {        
        var el = document.createElement("input");
        el.type = "text";
        el.value = value;         
    }
    if (elementType == 'checkbox') {
        // etc
    }

    return el;
}

function myvalue(elem, operation, value) {
    if (operation === 'get') {
        return $(elem).find("input").val();
    } else if (operation === 'set') {
        $('input', elem).val(value);
    }
}
Walter Stabosz
  • 7,447
  • 5
  • 43
  • 75
  • This seems to work. I'd like to try the other solution, before I mark an answer. Thanks, again. – bflow1 Sep 27 '11 at 17:43