Skip to content

OData plugin for jqGrid

Mark Babayev edited this page Jul 27, 2015 · 15 revisions

This plugin queries odata $metadata service and automatically generates jqGrid columns. It is the easiest way for implementing tables with basic CRUD operations, almost no code is required. In addition to simple column types this plugin supports odata ComplexTypes as well as odata NavigationProperties.

This plugin supports only the basic set of odata features. If you tried to run some query and it doesn't work, please open an issue and we will be happy to help you.

Both data and metadata can be provided as json or atom+xml. Atom+xml data can be received in this format:

<feed>
  <entry>
    <link>...</link>
    <content>
       <properties>...</<properties>
    </content>
  </entry>
</feed>

When data is provided in json format the jqGrid parameters like records, page, total, userdata can be obtained via odata annotations. Annotation object name is defined in annotationName: "@jqgrid.GridModelAnnotate" #Function parseMetadata
$.jgrid.odataHelper.parseMetadata(rawdata, dataType)
This is a generic function analogous to the .NET EdmxReader.Parse, it can be used in external packages too, not only in jqGrid.
It parses $metadata ajax response in xml/json format to the plain javascript object.

Function odataGenColModel

$("#grid").jqGrid({
  beforeInitGrid: function () {
    $(this).jqGrid('odataGenColModel', {...});
  }
});

This function generates jqGrid style columns by requesting odata $metadata. It is called by odataInit when gencolumns: true.

Arguments:

Name: default value Description
metadatatype: 'xml' ajax dataType, can be 'json', 'jsonp' or 'xml'(atom)
async: false set ajax sync/async for $metadata request (when calling from odataInit only async=false is supported)
entitySet: null required field, the name of the odata EntitySet
expandable: (link | json | subgrid*) the expansion type for ComplexTypes and NavigationProperties, for details see "odata colModel parameters".
metadataurl: (odataurl || p.url) + '/$metadata' set ajax url for $metadata request
successfunc: function() odataGenColModel callback to see when metadata request is over and jqGrid can be refreshed
parsecolfunc: function(options, data) event for converting parsed metadata data array in form of {name,type,nullable,iskey} to the jqGrid colModel array
parsemetadatafunc: function(data, status, xhr) event for converting unparsed metadata data (xml or json) to the jqGrid colModel array
errorfunc: function(data, message) error callback

Events:

Event name Description
jqGridODataParseMetadata the same as parsemetadatafunc
jqGridODataParseColumns the same as parsecolfunc

Function odataInit

$("#grid").jqGrid({
  beforeInitGrid: function () {
    $(this).jqGrid('odataInit', {...});
  }
});

This is the main plugin entry point function. It should be called before the colModel is initialized. When columns are defined manually it can be called from events beforeInitGrid or onInitGrid. When columns are created automatically it can be called from event beforeInitGrid only.
Even when gencolumns: true we can still add column definitions manually (colModel: colModelDefinition). Thus columns generated by $metadata will be overwritten by manual definitions.

Arguments:

Name: default value Description
gencolumns: false automatically generate columns from odata $metadata (calls odataGenColModel)
odataurl: p.url required field, main odata url
datatype: 'json' ajax dataType, can be json, jsonp or xml(atom)
entityType: null required field, odata entityType name
annotations: false use odata annotations for getting jqgrid parameters: page,records,count,total
annotationName: "@jqgrid.GridModelAnnotate" odata annotations class and namespace
version odata version (3/4), used to set $count=true or $inlinecount=allpages
errorfunc: function(data, message) error callback
metadatatype: datatype || 'xml' when gencolumns=true, alternative ajax dataType for $metadata request
odataverbs: {
    inlineEditingAdd: 'POST',
    inlineEditingEdit: 'PATCH',
    formEditingAdd: 'POST',
    formEditingEdit: 'PUT'
}
http verbs for odata and their corresponding actions in jqgrid (this feature requires thorough testing)

odata colModel properties

Name Description
isnavigation the column type is a NavigationProperty that points to another entity
iscomplex the column type is a ComplexType
iscollection the column is a Collection of entities that can be opened in a new subgrid
nosearch when true, this column is excluded from odata search
unformat: function (searchField, searchString, searchOper) works analogous to xmlmap/jsonmap, for example the function body can be:
function (searchField, searchString, searchOper) { return searchString !== '-1' ? 'cltype/Id' : null; }
expand: (link|json|subgrid*) defines data expansion types for complex and navigation properties, it works only with custom formatters specified in odata cmTemplates.
link the link to the property is displayed
json the property data is displayed in a json string form
subgrid the subgrid is opened when clicking on a link inside column (this feature is not available yet).

odata column templates (cmTemplate)

Name Description
odataComplexType column template for odata Complex type.
odataNavigationProperty column template for odata Navigation property.
#Custom cmTemplates
Plugin allows setting custom cmTemplates for any odata type
$.jgrid.cmTemplate["Edm.GeographyPoint"] = {
    editable: false,
    formatter: function(cellvalue, options, rowObject) {
        if (!cellvalue && this.p.datatype === 'xml') {
            var xmlvalue = $(rowObject).filter(function() {
                return this.localName.toLowerCase() === options.colModel.name.toLowerCase();
            });
            cellvalue = $.jgrid.odataHelper.convertXmlToJson(xmlvalue[0]);
        }
        if(cellvalue.crs && cellvalue.coordinates) {
           return $.jgrid.format('<div>{0}</div><div>[{1},{2}]</div>', cellvalue.crs.properties.name, cellvalue.coordinates[0], cellvalue.coordinates[1]);
        }
        return $.jgrid.format('<div>{0}</div>', cellvalue);
    }
};

Integration with datajs

Plugin can consume metadata generated by datajs package and build appropriate column definitions for jqGrid.

var odata = OData.parseMetadata(...);
var jqdata = $.jgrid.odataHelper.parseMetadata(odata, 'datajs');
var colModel = $('grid').jqGrid('parseColumns', jqdata['Products'], 'subgrid');

Examples

$("#grid").jqGrid({
    ...,
    beforeInitGrid: function () {
        $(this).jqGrid('odataInit', {
           annotations: false,
           metadatatype: 'xml',
           datatype: 'jsonp',
           version: 4,
           gencolumns: true,
           expandable: 'json',
           entitySet: 'Products',
           odataurl: "http://services.odata.org/V4/OData/OData.svc/Products",
           metadataurl: 'http://services.odata.org/V4/OData/OData.svc/$metadata',
           errorfunc: function (jqXHR, parsedError) {
               jqXHR = jqXHR.xhr || jqXHR;
               parsedError = $('#errdialog').html() + parsedError;
               $('#errdialog').html(parsedError).dialog('open');
          });
    }
});
$.ajax({
      url: 'http://services.odata.org/V4/OData/OData.svc/$metadata',
      dataType: xml,
      type: 'GET'
}).done(function(data, st, xhr) {
      var dataType = xhr.getResponseHeader('Content-Type').indexOf('json') >= 0 ? 'json' : 'xml';
      if(dataType === 'json') {
          data = $.jgrid.odataHelper.resolveJsonReferences(data);
      }
      data = $.jgrid.odataHelper.parseMetadata(data, dataType);
      var colModels = {};
      for (i in data) {
          if (data.hasOwnProperty(i) && i) {
             colModels[i] = $(this).jqGrid('parseColumns', data[i], 'subgrid');
          }
      }
      $("#grid").jqGrid({
        colModel: colModels['Products'],
        odata: {
           iscollection: true,
           subgridCols: colModels
        },
        ...,
        beforeInitGrid: function () {
            $(this).jqGrid('odataInit', {
               annotations: false,
               datatype: 'json',
               version: 4,
               gencolumns: false,
               entitySet: 'Products',
               odataurl: "http://services.odata.org/V4/OData/OData.svc/Products"
            });
         }
     });
});