Patch attached that supports 'sAjaxSource'. This means that a page will be rendered as quickly as possible and fetch the results using AJAX/JSON - I've tested it with caching enabled - which requires a slight workaround (i.e. delete the non-ajax cache cids) - the trick I've used is to limit the original results to a single record (which should enable token replacements from the first line) and then fetch the rest on an Ajax call.

Roughly what is involved in this patch:

  1. Adds a setting to the datatables style plugin to enabled "ajax_defer"; (possibly needs renaming)
  2. Provides a views query plugin that reduces the original view results to 1 record;
  3. Implements hook_views_post_execute(), which deletes the original single view result so that the ajax results will cache too;

Hopefully this is something that could be interesting incorporating into the module?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

RobinMofo’s picture

The next day ...

I did some further testing and everything works correctly on the first page load but subsequent visits take a while to display.
This is only appears to happen when caching is enabled - I'll be looking into it further.

RobinMofo’s picture

Attached is a much better patch which does away with the query plugin.
Instead there is a cache plugin which separates the results for the ajax call, works great and even includes a different key for filters.

I'm very happy, I look forward to hearing feedback.

RobinMofo’s picture

oops forgot patch!

duellj’s picture

Thanks for the excellent work, frobinrobin! I've had a little time to look through the patch, but haven't had a chance to apply it to test yet. There is a branch open in the repo to include ajax handling within DataTables (https://drupal.org/node/652800/git-instructions/ajax), would you mind taking a look to see if there's anything useful in that branch for you (it's been awhile since I've had a chance to work on it)?

I should have some time in the next few days to take a look at this fully.

Thanks!

RobinMofo’s picture

Thank you Duellj .. I've taken a look at the ajax branch but I don't see anything in yours that I don't have?
I think mine is a bit cleaner/simpler due to the cache plugin and additional option in your style plugin... but they look like they pretty much do the same thing... I've tested mine with Views ajax enabled and it's pretty sweet having views filters working in conjunction with an ajax datasource :)

I couldn't understand your ajax return, I'm presuming that it returns JSON via some internal magic? does the display cache that way? I have to say my output doesn't cache the final JSON, just the query (but the majority of a view operation is the query).

My next step was to get the expandable columns working with JSON, I do really like the format of the jquery file in the ajax brach and have been trying to work out how to integrate it with the DataTables callbacks in Drupal.datatables.dataTable:

    this.settings.fnPreDrawCallback = function( oSettings ) {
      console.log('fnPreDrawCallback');
    };
    this.settings.fnDrawCallback = function( oSettings ) {
      // preExpandable()
      console.log('fnDrawCallback');
    };
    this.settings.fnRowCallback = function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
      // addExpandRow
      console.log('fnRowCallback');
    };
    this.settings.fnInitComplete = function( oSettings, json ) {
      console.log('fnInitComplete');
    };

However, I'm not really strong with jquery so amending the existing code is a bit difficult for me - I'll have a go at it (Otherwise I'll never get better)

RobinMofo’s picture

Updated patch attached using aforementioned DataTable jquery callbacks for the table manipulation, specifically for enabling the Expandable rows.
'fnHeaderCallback' and 'fnRowCallback' were implemented in this patch, so the expanding works regardless of datasource.

This seems to work with both ajax and caching enabled.

duellj’s picture

Status: Needs review » Needs work

Starting to review this patch. A couple of notes:

I get this error with a basic view with no filters:

Notice: Undefined property: view::$exposed_input in template_preprocess_datatables_view() (line 373 of datatables.module).
+++ b/views/datatables.views.inc
@@ -28,5 +28,43 @@ function datatables_views_plugins() {
+ * Implementation of hook_views_query_alter

Should be:

Implements hook_views_query_alter().
+++ b/views/datatables.views.inc
@@ -28,5 +28,43 @@ function datatables_views_plugins() {
+  // do nothing if not enabled

Capitalize first word and end in period

+++ b/views/datatables.views.inc
@@ -28,5 +28,43 @@ function datatables_views_plugins() {
+    // enforce the settings from the view for dataable paths

Capitalize first word and end in period. misspelled datatable

+++ b/views/datatables_style_plugin.inc
@@ -173,5 +179,19 @@ class datatables_style_plugin extends views_plugin_style_table {
+    $form['datasources']['ajax_defer'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('sAjaxSource by this module'),
+      '#default_value' => !empty($this->options['datasources']['ajax_defer']),
+      '#description' => t('Do not render within the view but request data as Ajax request.'),

This title and description could use a little work. Maybe something like:

Title: Use AJAX
Description: Render results using AJAX instead of rendering all results initially. Useful when loading tables with lots of results.

+++ b/views/views_plugin_cache_defer.inc
@@ -0,0 +1,173 @@
+  function option_definition() {
+		$options = parent::option_definition();
+		return $options;
+	}
+	function options_form(&$form, &$form_state) {
+		parent::options_form($form, $form_state);
+  }

Use spaces instead of tabs.

+++ b/views/views_plugin_cache_defer.inc
@@ -0,0 +1,173 @@
+  function options_validate(&$form, &$form_state) {
+    //dpm($form_state, 'validating');
+  }

Remove method from class (not needed?)

+++ b/views/views_plugin_cache_defer.inc
@@ -0,0 +1,173 @@
+   * Implementation of get_output_key

Should be:

Implements parent::get_output_key().
+++ b/views/views_plugin_cache_defer.inc
@@ -0,0 +1,173 @@
+	/**
+   * Return a string to display as the clickable title for the
+   * access control.
+   */
+  function summary_title() {
+		$parent_title = parent::summary_title();
+  	return t('Duration !parent', array('!parent' => $parent_title));

Whitespace issues (trailing whitespace and tabs instead of spaces)

+++ b/views/views_plugin_cache_defer.inc
@@ -0,0 +1,173 @@
+  /**
+   * Initialize the plugin.
+   *
+   * @param view $view
+   *   The view object.
+   * @param views_plugin_display $display
+   *   The display handler.
+   */
+  function init(&$view, &$display) {
+  	parent::init($view, $display);

Use spaces instead of tabs

+++ b/views/views_plugin_cache_defer.inc
@@ -0,0 +1,173 @@
+   * validate exposed form data, only returning what we expect

Capitalize first word and end in period

+++ b/views/views_plugin_cache_defer.inc
@@ -0,0 +1,173 @@
+   * Because we're now caching "per filter", it's a good idea to set the cache ¶

Trailing whitespace.

+++ b/views/views_plugin_cache_defer.inc
@@ -0,0 +1,173 @@
+   * Obviouslya correctly configured CRON is required to clear stale cache

*Obviously

+++ b/views/views_plugin_cache_defer.inc
@@ -0,0 +1,173 @@
+    // just add our check and set duration here

Capitalize first word and end in period

duellj’s picture

Also, it looks like the AJAX callback returns all results, and doesn't take advantage of paging. It would be much better if it was able to use true AJAX for rendering results (i.e. only returns first x results, then pages through next results using AJAX). I tested with 10,000 entries and it took 7 seconds to load up.

Overall though this is looking like a very promising patch. I like your approach with using the views cache system to generate the query.

I'll be reviewing the JS next (this was all I could get to today).

Thanks for your work frobinrobin!

RobinMofo’s picture

Hi Duellj,

Thanks for the review, I've done the corrections in #7... I also updated my netbeans config to remove all trailing whitespace and use 2 spaces on 'continutation indentation'.

The reason it takes a fair time to load so many results is because it (sadly) doesn't cache the rendered JSON output.. depending on your field displays and if they require a lot to render; then it will add some load if you don't use page caching such as Varnish/Boost.
I've been considering why this occurs and how to fix it (or whether to cache it manually), I'm hoping that I just need to set the rendered JSON output as a variable in the cache class.

Would you like me to include Server Processing as an option? or would you prefer it to automatically add itself based on the current Views' pagination settings?

I'll start it as an option (easier) and will get back to you soon.

RobinMofo’s picture

Right, so for some reason I dealt with output caching first, I guess it bothered me more.. So now, output caching for JSON is working and is much faster, especially useful when you are retrieving all rows... my 1500 records dropped from 9 seconds to 3 seconds on the XHR request :)

There's a new option for 'Server Side Processing', which adds the missing 'bServerSide' datatables param - when you enable this, it uses the same callback path as 'AjaxDataSource' but you cannot cache with this option as it never updates (but with such small requests you shouldn't need to).

I also added a hook_views_view to remove the pager if the datatables one has been selected.

RobinMofo’s picture

I've been implementing this for a client and have (yet another!) updated patch.

The latest patch concentrates on bServerSide functionality and removes the styles' render method, improves the cache plugin so that cache keys are regenerated for the same view, which improves cache generation and enables datatables pagination.

The only outstanding issue is the "DataTables Search box" when bServerSide is enabled, datatables expects the server to do the filtering - which is managed by Views' filters and so its very specific to each View created by the user.
I'll need to take a look at the datatable API and see if there's an easy way to override/integrate with it, otherwise we might need to force the search box to be disabled when bServerSide is enabled?

I'll probably attach the latest patch within the next week or so.

jason.fisher’s picture

Are you still able to release that patch? I may have a good use case.

RobinMofo’s picture

I had to stop working on this approach and go another route.

My latest issue is that there is a huge performance gain when using an actual downloadable file (sAjaxSource) but I've mixed sAjaxSource with bProcessing, which in my patch, both work on a path.

I want to change the patch so that options relate better to functionality - providing the three cases:

  1. Select sAjaxSource, it creates a downloadable file.
  2. Select bProcessing and it uses Views processing by path, no file - views caching optional.
  3. Selecting both will specify the file path but will create the file based on arguments/filters selected (i.e. a more granular caching mechanism).

The options are a bit confusing and whilst we've tried to make them more explanatory, I think they need to mirror the datatable options.
So, there is a fair bit of work to get this into an ideal patch and I haven't any plans to work on this soon - but I don't think it would take massive amounts of time to sort out. My last thoughts were on the file downloadable part, which adds yet more time.

Otherwise if you can't wait then the patch in #10 should work fine, as long as you don't need the search options.

CarstenHarnisch’s picture

Issue summary: View changes
Status: Needs work » Needs review

Just looking on your patch I saw that you were at the end dropping the data as a "download" but running the render method ? The is definetly really slow as the template rendering will be get involved. Datatable can pretty easily work just with a JSON output.
As a first starting point I made a couple of modifications to the "ajax function" which creates the output.

function datatables_ajax($viewname, $display) {
  // retrieve the view and display
  $view = views_get_view($viewname);
  $view->init();
  $view->set_display($display);
  // localize $_GET for args and filters
  $get = $_GET;
  unset($get['q']);
  // get the arguments
  if (!empty($get['args'])) {
    $view->set_arguments($_GET['args']);
    unset($get['args']);
  }
  // get the rest of the filters
  if (!empty($get)) {
    foreach ($get AS $gk => $gv) {
      $view->exposed_input[$gk] = $gv;
    }
  }
  $style = $view->display_handler->get_plugin('style');
  // Set any pagination from datatables.
  if ($style->options['datasources']['server_processing']) {
    if (isset($_GET['iDisplayStart'])) {
      $view->set_offset($_GET['iDisplayStart']);
    }
    if (isset($_GET['iDisplayLength'])) {
      $view->set_items_per_page($_GET['iDisplayLength']);
    }
  }
  // Hide filters by exposing to block.
  $view->display_handler->override_option('exposed_block', array('default' => TRUE));
  // Execute view.
  $view->pre_execute();
  // this is important to let the view re-calculate the total-count !
  $view->get_total_rows = TRUE;
  $view->execute();
   
  // this is the output that the Datatables lib is
  // especting !
  // there is a problem that the view will do a fetchObject
  // but we would like to have an array. so lets strip this down
  $resData = array();
  foreach ($view->result as $rowObject)
  {
  	$resData[] = array_values((array)$rowObject);
  }
  
  $output['sEcho'] = isset($_GET['sEcho']) ? intval($_GET['sEcho']) : "";
  // as in the datatables docs iTotalRecords is the number of rows WITHOUT
  // filering and iTotalDisplayRecords is the filtered count. I do not
  // assume that we should stay with noth being the same
  $output['iTotalRecords'] = $view->total_rows;
  $output['iTotalDisplayRecords'] = $view->total_rows;
  $output['aaData'] = $resData;
  
  drupal_json_output($output);
  drupal_exit();
}

So feel free to add this to your patch also !

lklimek’s picture

Status: Needs review » Needs work

This issue definitely still needs some work (at least an answer to CarstenHarnisch's question) - and the correct status here is "needs work". "Needs review" means that there's a working patch awaiting for testing & committing if working well.

niteshdasari’s picture

Hi,

I get the latest ajax enabled datatables from the git using command
git clone --branch ajax http://git.drupal.org/project/datatables.git.

But i want to populate the json in view . how can i do that . please provide some inputs.

Thanks & Regards
Nitesh

niteshdasari’s picture

Hi,

Does any one integrated this patch to Datatables.if so could you please give some instructions on how to intrgrate this patch to existing datatables in drupal

joelstein’s picture

With the patch in #10, I was seeing lots of this error:

  • Notice: Undefined index: datasources in datatables_views_query_alter()

Here's an update patch which fixes that error (just a one line change on line 360 of the patch, if you want to compare them).

joelpittet’s picture

Status: Needs work » Needs review
joelpittet’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

It looks like the JS no-longer applies.

patching file datatables.module
Hunk #2 succeeded at 251 (offset 2 lines).
Hunk #3 succeeded at 267 (offset 2 lines).
Hunk #4 succeeded at 388 (offset 26 lines).
Hunk #5 succeeded at 442 (offset 26 lines).
patching file js/datatables.js
Hunk #1 FAILED at 3.
1 out of 2 hunks FAILED -- saving rejects to file js/datatables.js.rej
patching file views/datatables.views.inc
patching file views/datatables_style_plugin.inc
Hunk #3 succeeded at 45 with fuzz 2 (offset 3 lines).
Hunk #4 succeeded at 186 (offset 4 lines).
patching file views/views_plugin_cache_defer.inc
lazzyvn’s picture

If someone is looking for datatables ajax server side and Deferred rendering for speed use my custom module https://www.drupal.org/node/2845642
it support ajax for big data i tested with 10K lines

rpayanm’s picture

Status: Needs work » Needs review
FileSize
23.47 KB

rerolled

dqd’s picture

Version: 7.x-1.x-dev » 7.x-2.x-dev
Status: Needs review » Needs work

We should reroll the patch against latest 7.x 2.x dev

@lazzyvn: please let's merge forces and stop posting your sandbox project in every issue of this project. This isn't very helpful. Thanks for understanding.

dqd’s picture

Issue summary: View changes
Status: Needs work » Closed (outdated)

Due to inactivity for years and because of upcoming EOL of Drupal 7 I set it to Closed to cleanup the issue queue. Thanks for taking the time to report and all the hard work here from so many awesome users here and maintainers on this! Read more about EOL of D7 here: https://www.drupal.org/about/drupal-7/d7eol/partners

If this feature is still missing/required/wanted or somebody has some time and can reroll the patch against latest dev branch (2.x) feel free to reopen it.