1

I have the following JSON:

{
    "wrapper": {
        "table": {
            "rows": [
                {
                    "cells": [
                        {
                            "fname": "Jack",
                            "label": "fname",
                            "editable": false
                        },
                        {
                            "lname": "Kalra",
                            "label": "lname",
                            "editable": true,
                            "details": [
                                {
                                    "industry": "music"
                                },
                                {
                                    "industry": "media"
                                }
                            ]
                        }
                    ]
                },
                {
                    "cells": [
                        {
                            "fname": "Steven",
                            "editable": true,
                            "label": "fname"
                        },
                        {
                            "lname": "Martini",
                            "editable": true,
                            "label": "lname"
                        }
                    ]
                },
                {
                    "cells": [
                        {
                            "fname": "Andrea",
                            "editable": true,
                            "label": "fname"
                        },
                        {
                            "lname": "Dmello",
                            "editable": true,
                            "label": "lname",
                            "details": [
                                {
                                    "industry": "finance"
                                },
                                {
                                    "industry": "HR"
                                },
                                {
                                    "industry": "media"
                                }
                            ]
                        }
                    ]
                },
                {
                    "cells": [
                        {
                            "fname": "James",
                            "label": "fname",
                            "editable": false
                        },
                        {
                            "label": "lname",
                            "lname": "Diamond",
                            "editable": true,
                            "details": [
                                {
                                    "industry": "music"
                                },
                                {
                                    "industry": "media"
                                }
                            ]
                        }
                    ]
                },
                {
                    "cells": [
                        {
                            "fname": "Aba",
                            "label": "fname",
                            "editable": true
                        },
                        {
                            "label": "lanme",
                            "lname": "Duck",
                            "editable": true,
                            "details": [
                                {
                                    "industry": "finance"
                                },
                                {
                                    "industry": "technology"
                                },
                                {
                                    "industry": "media"
                                }
                            ]
                        }
                    ]
                },
                {
                    "cells": [
                        {
                            "fname": "Henry",
                            "label": "fname",
                            "editable": true
                        },
                        {
                            "label": "lname",
                            "lname": "Hebert",
                            "editable": true,
                            "details": [
                                {
                                    "industry": "finance"
                                },
                                {
                                    "industry": "HR"
                                },
                                {
                                    "industry": "media"
                                },
                                {
                                    "industry": "IT"
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    }
}

All cells are editable.

I'm trying to loop through each row and then each cell to find out the number of properties in "details". In inline editing mode, it should be a text field and the value of text field should be the corresponding number of properties.

Example - for Marc Kalra, the details cell will be a text field with a value of 2.

Here's my code

loadComplete: function(data){
   var x, y, cellProp;
   for (x = 0; x < data.wrapper.table.rows.length; x++) {
      var cellCount = data.wrapper.table.rows[x].cells.length;      
      for (y = 0; y < cellCount; y += 1) {
           cellProp = data.wrapper.table.rows[x].cells[y];             
           var prop, listCount, cellLabel;
           listCount = data.wrapper.table.rows[x].cells[y].details.length;
           cellLabel = data.wrapper.table.rows[x].cells[y].label;
           function gridCustomEdit (value, options){                                                                                    
        var el = document.createElement("input");
        el.type="text";
        el.value = listCount;
        return el;
        }       
        for (prop in cellProp) {                                                    if (prop === "details"){
                                    $("#jqgrid").setColProp(cellLabel, {
        editable: true,
        edittype: "custom",
                                        editoptions: {
                                            custom_element: gridCustomEdit                                  
                                        }
                                    });
                                }
                            }                       
                        }
}

PROBLEM - is that el.value = listCount; in the above code always returns 4 as the number of properties for each row/cell.

Can someone point me my mistake?

UPDATED

loadComplete: function(data){
   var x, y, cellProp;
   for (x = 0; x < data.wrapper.table.rows.length; x++) {
      var cellCount = data.wrapper.table.rows[x].cells.length;      
      for (y = 0; y < cellCount; y += 1) {
           cellProp = data.wrapper.table.rows[x].cells[y];  
           var isEditable = cellProp.editable;
           if (isEditable === false) {
                $("#jqgrid").setColProp(cellProp.label, {
                    editable: false
                });
           }else {           
              var listCount, cellLabel;
              listCount = data.wrapper.table.rows[x].cells[y].details.length;
              cellLabel = data.form.summary.rows[x].cells[y].label;
              $("#jqgrid").setColProp(cellLabel, {
                   editable: true,
                   editoptions: {
                       dataInit: function(elem){
                          $(elem).myPlugin({listCount: listCount})
                       }
                   }
              })                              
           }                                        
       }                       
   }
}

PLUGIN CODE

(function( $ ){     
    $.fn.extend({   
        myPlugin: function(options){
            var defaults = {
               listCount: 0
            };
            var options = $.extend(defaults, options);
            var o = options;
            alert(o.listCount);

           if (o.listCount === 3){
              $(elem).html("<input type='text' value='" + o.listCount + "'>")
           } else {
              $(elem).html("<select>") **// this should be a dropdown with values = properties of `details`** 
           }
        }
    })
})

GRID CODE

$("#jqgrid").jqGrid({
    datatype: "json",
    colNames:['fname','lname'],
    colModel:[
      {name:'fname',index:'fname'},
      {name:'lname',index:'lname'},
    ],
    jsonReader: {
       root: "wrapper.table.rows",
       repeatitems: false
    },
    onSelectRow: function(id){
       $(this).jqGrid('editRow',id);
    },
})

If details exist + number of properties in details = 3, then lname is displayed as a text field in inline editing mode.

If details exist + number of properties in details > 3, then lname is displayed as a select field in inline editing mode.

techlead
  • 779
  • 7
  • 24
  • 44
  • Start searching for "JavaScript function in a loop." JavaScript does not have block scope - only function scope - so Weird Things typically happen when you try to define a function in a loop. See http://stackoverflow.com/questions/3037598/how-to-get-around-the-jslint-error-dont-make-functions-within-a-loop and http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – Matt Ball Nov 28 '11 at 22:49
  • Thanks for your reply! I checked my code and everything seems fine unless I'm overlooking something. – techlead Nov 28 '11 at 23:16
  • It's the `gridCustomEdit` function. – Matt Ball Nov 28 '11 at 23:26
  • Yes, I took it out of `loadComplete: function(data)` and passing parameter when calling `gridCustomEdit` -- `custom_element: gridCustomEdit(listCount)`. It's giving me a value of undefined now. – techlead Nov 28 '11 at 23:33

1 Answers1

2

The method setColProp set property for the column and not for the cell in the column. So if you set in the loop setColProp for the same column many times only the last setting will be applied. Because the last row (for "Love Hebert") in your data has 4 items in the details array only the value will be used.

The next error is that you define gridCustomEdit function which has reference to external variable listCount. In the case there are only one instance of the function with the last value of the variable. If you need to have many function instances with different values you should use closure.

In your case it seems to me you can implement all what you need even without the usage of closure and without custom editing (edittype:'custom' with custom_element and custom_value).

I suppose that all what you need to do is to set setColProp inside of onSelectRow (or before the call of editRow) and not inside of loadComplete. See the answer for more information. If you need to change the edittype of the column you can do this in the same way. So you can for example dynamically set edittype: "text" and set editoptions with dataInit which change the value of the element.

If it is needed you can even dynamically switch the edittype between edittype: "text" and edittype: "select" and set all editoptions which are required.

In the way you will receive simple and flexible code which don't use custom editing at all.

Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Please see code under **UPDATED** in my original post. I'm trying to pass the number of properties in `details` to the plugin. So, when I do inline edit for row #1, a value of 2 should be passed to the plugin. When I do inline edit for row #2, a value of 3 should be passed to the plugin. Can you please help me fix my code? I'm kinda confused at this point on how to use `setColProp`. – techlead Nov 29 '11 at 16:18
  • @SK11: You make the same error as before in the `UPDATED` part of the question. You overwrite the value of `editable` property and other. You code is like `x = 1;/*for the first row*/ x = 3;/*for the second row*/ x = 4;/*for the third row*/ x = 2;/*for the 4-th row*/` At the end the value for `x` will be 2. All previous setting of `x` was absolutely not important. If you set `editable` property to `true`, then to `false` and so on, only the last setting will be saved and used later because **it's not property of the row (the column in the row), it's just property of the column** . – Oleg Nov 29 '11 at 16:35
  • @SK11: Like I wrote you before you should set the property of column *directly before* you set the row or the cell in the editing mode. The exact code depend on the editing form which you use and how exactly you this do. You should just include **full code** which you use. Then I can show which changes you will have to do. By the way the usage of `pluginName` in the form how you as posted has absolutely no sense. – Oleg Nov 29 '11 at 16:47
  • @SK11: You don't posted **the full code which define the grid**. You posted only the code of `loadComplete`. Which [editing mode](http://www.trirand.com/jqgridwiki/doku.php?id=wiki:jqgriddocs#editing) you use? Where are the corresponding code? – Oleg Nov 29 '11 at 17:26
  • I'm using inline editing mode. I have updated the post with grid code and logic in plugin. – techlead Nov 29 '11 at 17:49
  • 1) To use inline editing you should call `editRow` somewhere the your code. 2) You try to set property (in the code `$("#jqgrid").setColProp(cellLabel, ...`) of the column with the name `cellLabel`, where `cellLabel = data.wrapper.table.rows[x].cells[y].label`, but your JSON data has no `"label"`. Probably you want to set property of `"industry"` column, but you have also no `"industry"` column in the grid. Which column in the grid you want to have additionally to 'fname' and 'lname'? – Oleg Nov 29 '11 at 18:12
  • (1) Yes, I'm calling editRow. `$("jqgrid").editRow(editRowID);` (2) This was an oversight. I added the `label` property in json (3) there are only 2 columns in the grid - `fname` and `lname`. – techlead Nov 29 '11 at 18:28
  • **Where in your code you call `editRow`?** The code which you posted don't contain the call. Before the call you can change and column properties. If you set `listCount` as the `value` of `` element then the user will see integer like "3" **instead of** the name like "Henry". What will be after the value will be saved? I see no sense to place other information as the current cell value in the `` or select field. – Oleg Nov 29 '11 at 19:11
  • @SK11: Now you define in the JSON input only one column: either "fname" or "lname". The second column is empty. Moreover the JSON data contain no `id` property. How you will identify the modified data on the server? Where you defined `editurl` in the grid? Which relation has `"industry"` to the person name? All the example seems not natural. Do you really have a problem which you want to implement or you just play with jqGrid? – Oleg Nov 29 '11 at 20:25
  • I have no intentions of wasting my time or anybody else's. I appreciate your time and efforts to help me. I must add, however, that **you are asking me questions beyond my requirements such as Which relation has `"industry"` to the person name?** I will check my code in the post again, if I have missed out on anything. But I'm pretty sure that I have specified all the requirements. – techlead Nov 29 '11 at 20:29
  • @SK11: In any way I recommend you to use some clear `"id"` in the JSON data which full identify the row. Then you could save the information from the JSON data about editing in an object defined in the outer scope (global variable for example). Inside of `onSelectRow` you get from the object the properties for all columns, set there with respect of `setColProp` and then call `editRow`. The schema will work. – Oleg Nov 29 '11 at 20:45
  • @SK11: I recommend you forget plugin. It gives no advantages. Just include `id` in your JSON data. You defines `var myColProp = {};` before grid definition and use `myColProp[data.wrapper.table.rows[x].cells[y].id] = data.wrapper.table.rows[x].cells[y];` inside of `loadComplete`. If the user select a row the callback `onSelectRow` will be called. You get `id` as parameter. So you can use `myColProp[id]` contains all the data which you need. So he you can call `setColProp` and then call `editRow`. – Oleg Nov 29 '11 at 21:19
  • @SK11: I have of course no existing demo which do what you need. Moreover I tried explained you that I don't understand the sense of toggling between input field and select field. In any way it has no sense for the JSON data which you posted till now. If you would have the column `industry` I can imagine that you want to have "personal" select list for every cell. Nevertheless I would be use [dataUrl](http://www.trirand.com/jqgridwiki/doku.php?id=wiki:common_rules#editoptions) column option in the case with the row id as parameter. So one would have "personal" select list and small clear code. – Oleg Nov 29 '11 at 21:34
  • @SK11: I don't understand you wish to use jQuery plugin in the case. I see no sense in such plugin. It's like you would ask me to help to to play piano with additional requirement to use hammer in any way. The hammer is useful, but not in case of playing piano. If you really want to save some state in the row itself (in the `` element) you can use [jQuery.data](http://api.jquery.com/data/) for example. You can save the data in the grid using `$("#jqgrid").jqGrid('setGridParam', 'anyNameOfYourCustomParameter', anyObjectWhichYouWantToSave);` – Oleg Nov 29 '11 at 21:41
  • @SK11: But I decide what *I do* in general and on the site. So if you receive the project and are not able even to discuss the requirements - it's *your* problem. Finally you will receive the money for the job. – Oleg Nov 29 '11 at 21:51
  • I know what I'm doing, Oleg. JSON that I posted is absolutely correct and I actually integrated the plugin and that too `onSelectRow` with the functionality that is required - toggling between input and select field. So, yes it was my problem and I fixed it myself, because I believe there is nothing that technology cannot solve. Thanks for your time and your rude comments. – techlead Nov 30 '11 at 17:58