title: How do I load data into Kendo UI Grid using server side paging?
body: <p>I have the following code that builds a kendo ui grid:</p>
  
  <pre><code>    // build grid columns
  
      // the check box column is always visible for all users
      var columns = [{
          field:'&lt;input id="masterCheck" class="check" type="checkbox" /&gt;&lt;label for="masterCheck"&gt;&lt;/label&gt;', 
          template: '&lt;input class="check rowSelect" id="${id}" type="checkbox" /&gt;&lt;label for="${id}"&gt;&lt;/label&gt;',
          filterable: false,
          width: 33,
          sortable: false // may want to make this sortable later. will need to build a custom sorter.
      }];
  
      // build the rest of the columns using data provided by the server
      var metrics = initialData.metric;
      for (var i=0; i &lt; metrics.length; i++) {
          var metric = metrics[i];
          var column = {};
          column.field = metric.qualifiedName;
          column.title = metric.label;
          column.width = metric.colWidth;
          // initially hide all columns. we'll know exactly which ones to show after a search
          column.hidden = true;        
          column.type = metric.type;
  
          // handle special considerations
          if (column.type === 'float' || column.type === 'int') {        
  
              // format all floats to two decimal places
              if (column.type === 'float') {
                  column.format = '{0:n2}';
              }
              // the grid only has a type of number.            
  
              column.attributes = {'class' : 'right-align'};
  
              var field = column.field;
  
              // create a closure to build a function that captures the field variable value
              // in this iteration. Immediately execute the anonymous outer function so 
              // that the inner function is returned as assignment to the footerTemplate
              // variable. The param data will be passed to the function by the grid.
              // That function then executes the buildFooter which has the right field value
              // due to the closure. notice that each invocation of the outer function
              // creates a new scope chain that adds a new inner function.
              column.footerTemplate = (function(field, columnType) {return function() { return buildFooter(field, columnType); }; })(field, metric.type);
              column.type = 'number';
  
          } else if (column.type === 'date') {
              column.format = '{0:yyyy-MM-dd}';
          } else if (column.field === 'attachments') {
              //column.field = 'text';
              // use a template defined in search.jsp to style this complex
              // object
              column.template = kendo.template($('#attachmentTemplate').html());
              column.sortable = false;
              column.filterable = false;
          } else if (column.type === 'list') {
              column.type = 'string';
          }
  
          columns.push(column);        
      }
  
      var toolbarItems = [{ name: 'custom', text: 'Filter', className: 'filterClass k-state-disabled', imageClass: 'k-icon k-i-funnel'},
                          { name: 'view', text: 'View', className: 'viewClass k-state-disabled', imageClass: 'k-icon k-i-search' }];
      // only show build the edit and delete buttons in the toolbar if the
      // user has permissions
      if ($('#hasAdminControls')[0]) {
          toolbarItems.push({ name: 'edit', text: 'Edit', className: 'editClass k-state-disabled' });
          toolbarItems.push({ name: 'destroy', text: 'Delete', className: 'deleteClass k-state-disabled' });
      }
  
      var options = {
  
          autoBind: false,
          dataBound: function() {
  
              alert('dataBound');
              for(var i =0; i &lt;  checkedRows.length; i++){
                  $('#'+ checkedRows[i]).attr('checked','checked');
              }            
              $('.rowSelect').click(setGridControlsState);
              setGridControlsState();
  
              $('.k-grid-content').removeHighlight();
              $('.k-grid-content').highlight(uniqueHighlights);
          },    
           dataSource: {
              //type: 'json',
              //batch: 'true',
              serverPaging: true, // we may need to use paging for performance reasons
              //schema: {
              //    total: 'total'//function(response) { console.log(response); alert('hi2'); return 500; }
              //},
              //schema: {
                  //model: Acquisition // if we use a model then complex objects' fields all have string type
  
              pageSize: 10, 
  
              //serverFiltering: true, // we may want to use this in the future if client filtering becomes a performance issue
              //serverSorting: true, // we may want to use this in the future if client sorting becomes a performance issue
              transport: { read: 
              function(options) {
  
                  var setupOptions = { 
                          success: function(data, statusText, xhr, $form) {options.success(data); loadSearch(data, statusText, xhr, $form)},
                          type: 'POST',
                          dataType: 'json',
                          data: {skip: options.data.skip, take: options.data.take},
                          url:   '../search.x',
                          error: errorHandler.handle,
                          timeout: 50000
                  };
                  $('#searchForm').ajaxSubmit(setupOptions);
              }
  
              }
          },
          height: 600,
          pageable: {
              //numeric: false,
              //previousNext: false,
              messages: {
                  display: "{2} Acquisitions"
              },
              pageSizes: true
          },
          sortable: true,
          resizable: true,
          filterable: true,
          toolbar: toolbarItems,
          columns: columns
      };
  
      // create the grid using the above options
      $('#resultsGrid').kendoGrid(options);
  
      // for purely aesthetic purposes, move the toolbar to the bottom (by default it's at the top) 
      $('#resultsArea').find('.k-grid-toolbar').insertAfter($('#resultsArea .k-grid-footer'));
      var grid = $('#resultsGrid').data('kendoGrid');
      grid.refresh();
  </code></pre>
  
  <p>The grid is initially hidden but shows after a search form is submitted. When the search form is submitted, the following function is executed:</p>
  
  <pre><code>function startSearch(evt) {
      evt.preventDefault();
  
      showLoadingGrid();
      var grid = $('#resultsGrid').data('kendoGrid');
      grid.dataSource.read();
  
  }
  </code></pre>
  
  <p>The grid.dataSource.read() function call will result in the AJAX call to the server initiated by transport.read. However, the success function never gets called because kendo throws an error. It states d.oneOfMyObjects is undefined kendo.web.min.js (line 9). When I look at the json response, I have several json objects from the server. One of the objects is an array of objects. Each of those objects has an property (which is an object) called oneOfMyObjects. Each oneOfMyObjects is non-null. So, I'm not sure why kendo is failing. I'm using kendoui.2012.3.1315. How can I stop kendo from throwing this error and allow my loadSearch callback function to be called?</p>
  
  <p><strong>2nd EDIT</strong>
  The error is occurring in the success function at options.success(data);</p>
  
  <p><strong>EDIT</strong>
  Editing question to contain the output from server. Please note that the same output works fine without sever pagination (also had to modify output for data security purposes... I tried to keep the same structure though but hopefully I did not accidentally change to make it non-JSON compliant):</p>
  
  <pre><code>{
      "total":500,
      "displayFields":["summary","page","take","pageSize","skip"],
      "object":[{
          "id":16835,
          "date":-2208967200000,
          "type":"Needs Value",
          "nestedObject1":{
              "id":16870,
              "name":"Not Specified",
              "region":{
                  "name":"Needs Value"
              }
          },
          "oneOfMyObjects":{
              "id":16923,
              "name":"Needs Value"
          }
      }, {
          "id":16836,
          "date":-2208967200000,
          "type":"Needs Value",
          "nestedObject1":{
              "id":16873,
              "name":"Not Specified",
              "region":{
                  "name":"Needs Value"
              }
          },
          "oneOfMyObjects":{
              "id":16925,
              "name":"Needs Value"
          }
      }, /* 8 more records */]
  }
  </code></pre>
  
  <p><strong>3rd edit to include loadSearch function</strong></p>
  
  <pre><code>function loadSearch(data, statusText, xhr, $form, options) {
  
      if (data.validationError) {
          // TODO we need to look at the message from the reply
          // right now though only date validation errors will exist
          dialog.show('Error', 'Please enter dates formatted as yyyy-mm-dd.');
          global.loadingIndicator.hide();
          return;
      }
  
      checkedRows = [];
      var object= data.object;
  
      var grid = $('#resultsGrid').data('kendoGrid');
  
      // clear any filters. This also help with an issue where no 
      // rows are shown due to a filter.
      grid.dataSource.filter({});
  
  
      // set the search results data in the grid
      grid.dataSource.data(object);
  
      // show columns that are either a user preference
      // column (or default set if user has no preferences)
      // or a field matching search data
  
      // let's only hide/show the delta between
      // previously viewed cols and new cols to display 
      // since it's much faster than hiding all old
      // and then displaying all new cols
      var oldCols = $('#displayColumns').val() || [];
  
      // the server tells the UI which fields to display
      // based on user preference and fields that that
      // have matching search data
      var newCols = data.displayFields;
  
      var removedCols = oldCols.diff(newCols);
      for (var i in removedCols) {
          $('#displayColumns option[value="' + removedCols[i] + '"]').removeAttr('selected');
          grid.hideColumn(removedCols[i]);
      }
  
      var addedCols = newCols.diff(oldCols);
      for (var i in addedCols) {
          grid.showColumn(addedCols[i]);
          $('#displayColumns option[value="' + addedCols[i] + '"]').attr('selected', 'selected');
      }
  
      // we have to tell the chosen overlay that we updated the list
      $('#displayColumns').trigger('liszt:updated');
  
      // we have to keep track of the current selected values
      // so that when the user changes to selection we'll 
      // be able to compare to the original selection
      // and now what they changed.
      $('#displayColumns').data('chosen-values', $('#displayColumns').val());
  
  
      // display the results
      grid.refresh();
  
      realignFooter();
  
      // Highlight search matches so the user can easily see
      // why the record is in the result grid.
      // Unfortunately, the highlights library takes a comma-delimited list.
      // It's problematic when the search results contain a comma.
  
  
      // remove previous highlights
      //$('.k-grid-content').removeHighlight();
  
      uniqueHighlights = data.uniqueHighlights || [];
      $('.k-grid-content').removeHighlight();
      $('.k-grid-content').highlight(uniqueHighlights);
  
      // reset the controls since all checkboxes have been cleared
      setGridControlsState();
  
      // register event to capture clicks on grid checkboxes
      // we can't do this during initialization b/c the checkboxes
      // are not yet built. Note: we don't have to remove
      // the events associated with previous checkboxes as 
      // jquery should automatically do this.
      $('.rowSelect').click(setGridControlsState);
  
      // remove loading indicator
      global.loadingIndicator.hide();
  
      // style the UI to give the user an option to save the columns again
      $('#saveCols &gt; span').empty().text('Save Columns');
      $('#saveCols').removeClass('k-state-disabled');
  
  }
  </code></pre>