0

When using jqGrid and JSON server responses, I seem to be having a problem getting my JSON mapping correct.

For example, my server response looks like this:

[
     {ID: 'cmp1', Name: 'Name1', Address: 'Address1', Phone: 'Phone1', Agent: 'Agent1', last_trx: 'last_trx1'}, 
     {ID: 'cmp2', Name: 'Name2', Address: 'Address2', Phone: 'Phone2', Agent: 'Agent2', last_trx: 'last_trx2'}
]

and my jqGrid settings look like this (local datatype and local dataset used for testing):

    var grid = $('#grid_id');
    grid.jqGrid({
        datatype: 'local',
        colNames: ['ID', 'Company Name', 'Location', 'Phone', 'Agent', 'Last Load'], 
        colModel: [
            {name: 'ID', index: 'ID', jsonmap: 'ID', width: 75}, 
            {name: 'Company Name', index: 'Name', jsonmap: 'Name', width: 150}, 
            {name: 'Location', index: 'Address', jsonmap: 'Address', width: 150}, 
            {name: 'Phone', index: 'Phone', jsonmap: 'Phone', width: 125, align: 'center'}, 
            {name: 'Agent', index: 'Agent', jsonmap: 'Agent', width: 150}, 
            {name: 'Last Load', index: 'last_trx', jsonmap: 'last_trx', width: 150}
        ], 
        loadonce: true, 
        shrinkToFit: false, 
        width: 600, 
        rowNum: 20, 
        rowList: [10, 20, 30, 40, 50, 100], 
        repeatitems: false, 
        jsonReader: { repeatitems: false, id: '0' }, 
        pager: '#companies_pager', 
        caption: 'Company List', 
        data: [
            {ID: 'cmp1', Name: 'Name1', Address: 'Address1', Phone: 'Phone1', Agent: 'Agent1', last_trx: 'last_trx1'}, 
            {ID: 'cmp2', Name: 'Name2', Address: 'Address2', Phone: 'Phone2', Agent: 'Agent2', last_trx: 'last_trx2'}
        ]
    });

ID, Phone, and Agent all show up (as their datasource names are exactly the same). However, Company Name, Location, and Last Load are all not being displayed. I thought that using jsonmap along with jsonReader: { repeatitems: false} allowed you to have different names for your JSON object than your colNames object.

All help would be greatly appreciated.

UPDATE Sorry for the late update. This is how the code will look out of testing. _data.rows is an array of JSON objects.

var noRecords = $('<div>No results for the entered company name.</div>');
        grid.jqGrid({
            datatype: 'local',
            colNames: ['ID', 'Company Name', 'Location', 'Phone', 'Agent', 'Last Load'], 
            colModel: [
                {name: 'ID', jsonmap: 'ID', width: 75}, 
                {name: 'Company Name', jsonmap: 'Name', width: 150}, 
                {name: 'Location', jsonmap: 'Address', width: 150}, 
                {name: 'Phone', jsonmap: 'Phone', width: 125, align: 'center'}, 
                {name: 'Agent', jsonmap: 'Agent', width: 150}, 
                {name: 'Last Load', jsonmap: 'last_trx', width: 150}
            ], 
            loadonce: true, 
            shrinkToFit: false, 
            width: 600, 
            rowNum: 20, 
            rowList: [10, 20, 30, 40, 50, 100], 
            repeatitems: false, 
            jsonReader: { repeatitems: false, id: '0' }, 
            pager: '#companies_pager', 
            caption: 'Company List', 
            loadComplete: function() {
                if(grid[0].p.reccount === 0) {
                    noRecords.show();
                }
                else {
                    noRecords.hide();
                }
            }
        });
/* Get the list of companies based on the search criteria */
function getCompanies() {
    var company = document.getElementById('company').value;
    if((company != '') && (company != oldCompany)) {
        oldCompany = company;
        myAjax('get', {method: 'getCompanies', a: 'companies', data: company}, callbackGetCompanies);
    }
}
/* Parse the server response */
function callbackGetCompanies(_data) {
    if(_data && _data.message) {
        if(_data.message == 'true') {
            grid.jqGrid('clearGridData').jqGrid('setGridParam', {data: _data.rows, page: 1}).trigger('reloadGrid');
        }
        else {
            dialog(_data.message);
        }
    }
    else {
        serverError();
    }
}
Kyle
  • 4,421
  • 22
  • 32

1 Answers1

2

You have more as one problem in the demo.

  1. If you use datatype: 'local' the input data from the data parameter will be managed by localReader and not jsonReader. The value of repeatitems of localReader is by the way already false. So correct will be to use localReader: { id: 'ID' }.
  2. If you use datatype: 'local' the loadonce: true option will be ignored because the data will be already local and should not be loaded once from the server.
  3. If you use datatype: 'local' the jsonmap will be ignored. The property will be used only in case of datatype: 'json' or datatype: 'jsonstring'.
  4. If you use datatype: 'local' the value of index property have to be the same as the value of name property. Only in the case the local sorting will work correctly.
  5. You should not use spaces ' ' inside of name property. No meta-characters can be inside of name property.

So you have to use name to the name of the property in the data array:

colModel: [
    {name: 'ID', index: 'ID', width: 75},
    {name: 'Name', index: 'Name', width: 150},
    {name: 'Address', index: 'Address', width: 150},
    {name: 'Phone', index: 'Phone', width: 125, align: 'center'},
    {name: 'Agent', index: 'Agent', width: 150},
    {name: 'last_trx', index: 'last_trx', width: 150}
],
localReader: { id: 'ID' },

I see no reason why you should need to have name property other as in the input data.

Oleg
  • 220,925
  • 34
  • 403
  • 798
  • I have updated my post now to show how it will actually be used. Using this, there will be no actual `datatype: 'local'` use. The `datatype` will be changed to json when reloading the grid. Am I incorrect in thinking that the `name` option of `colModel` should be the corresponding name in the `colNames` array? – Kyle Mar 26 '12 at 12:26
  • Using the `colModel` you posted did work (and I had tested it earlier as well), but was just confused as to why the original didn't work. As my previous comment says, I am confused to the difference of the `name` attribute and `jsonmap` attribute of the colModel. – Kyle Mar 26 '12 at 12:35
  • 1
    @Kyle: What I still don't understand: why you use `myAjax` and `datatype: 'local'` instead of loading usage of `datatype: 'json'` the data directly from the server? The `name` option is free identifier of the column. It will be used to constructs ids in many cases. So its name should corresponds to id naming rules. It you use named properties as input, then in case of `datatype: 'local'` you should choose the `name` property the same as in the input data. If you use `datatype: 'json'` you can use `jsonmap` to which describes how to get the value for the column from the input item of data. – Oleg Mar 26 '12 at 13:05
  • I use the custom Ajax loader because there are server messages returned in case of errors or invalid inputs from the user. In the event of an error, I want the user to know this instead of just displaying "no results". Thank you for explaining the `name` property of colModel. Your answers to other questions have helped me greatly already. – Kyle Mar 26 '12 at 13:21
  • 1
    @Kyle: You are welcome! jqGrid have two callbacks: `loadComplete` called in case of successful server response and the `loadError` called in case of error. The format of the server response with the error message can be absolutely another as the successful server response. You should just set any error HTTP code in the server response. See [here](http://stackoverflow.com/a/6969114/315935) for more details. – Oleg Mar 26 '12 at 13:33
  • The `loadComplete` and `loadError` functions are great, but the contents of the data object passed into `loadComplete` is stripped of the custom response message. For example, a response from the server might look like: `{"message":"Some message for the user.","rows":[],..}`. When using `loadComplete:function(data)`, the data object only contains page, records, rows, total, and userdata. It does not contain the full server response. I know the `loadError` function will do this, but no error codes are thrown as the request was technically successful. – Kyle Mar 26 '12 at 13:53
  • 1
    @Kyle: The `data` parameter of `loadComplete` of the `data` parameter of `beforeProcessing` do contains *full* server response with all your custom extensions. It's important that you should use `datatype: 'json'` and not `'local'`. Only if you use `loadonce: true`, then the parameter contains the server response only at the first time when the data are loaded really from the server. I don't understand what you mean under the last sentence of your comment "no error codes are thrown as the request was technically successful". – Oleg Mar 26 '12 at 14:00
  • `beforeProcessing` was exactly what I needed! Thank you again! Once again, one of your answers has solved my problems. My "no error codes are thrown..." sentence just meant that the status code was always 200. – Kyle Mar 26 '12 at 14:25
  • 1
    @Kyle: You are welcome! You can set the status code explicitly to any value. I don't use PHP myself, but `http_response_code(400);` for example should do this. You can use [header](http://php.net/manual/en/function.header.php) alternatively. – Oleg Mar 26 '12 at 14:37