Hi,

I was running into a problem yesterday when a client asked me to create a button who will send the result of a form to Drupal on server A, and then, with the result of that, it needs to be sent to server B.
I've been asked why the server A cannot communicate directly with the server B and for some reason, it's not possible.

I've created a small patch of 10 lines max for CTools to allows people to create callbacks.

Another solution would have been to create two recursive $.post(), but I wanted to see if I could do it with CTools before.

How does it works ?

First, you need to create a link, having the 'ctools-use-ajax' class.

Then, add the js corresponding:

ctools_add_js('ajax-responder');

Now let's see the callback code of that menu entry:

function ctoolscallback_callback($js = FALSE) {
  if ($js) {
    ctools_include('ajax');
    $commands[] = ctools_ajax_command_callback('mycallback', time());
    ctools_ajax_render($commands);
  }
}

If you run this, nothing will happend because your callback 'mycallback' is not defined.
To do this, you have to define it in a JS file like this:

Drupal.CTools.AJAX.commands.callback.mycallback = function(data) {
  alert("This is my custom callback: " + data.data);
}

This will return a popup box with the text and the value of the function 'time()' previously runned in PHP.

Patch for CTools 6.x-1.x is following.

I've created a small module to test my patch, here it is:

function ctools_callback_menu() {
  $items = array();

  $items['ctoolscallback/%ctools_js/go'] = array(
    'page callback' => 'ctoolscallback_callback',
    'page arguments' => array(1),
    'access arguments' => array('access content')
  );

  return $items;

}

function ctools_callback_block($op = 'list', $delta = 0, $edit = array()) {
  switch ($op) {
    case "list":
      $block = array();
      $block[0]['info'] = t('Ctools Callback');
    break;
    case "view":
      $block['subject'] = t('Ctools Callback');
      $block['content'] = _get_block_content();
      break;
  }

  return $block;

}

function _get_block_content() {
  $output = l('Ctools callback', 'ctoolscallback/nojs/go', array('attributes' => array('class'=>'ctools-use-ajax')));
  ctools_add_js('ajax-responder');
  return $output;
}

function ctoolscallback_callback($js = FALSE) {

  if ($js) {
    ctools_include('ajax');

    $commands = array();
    $commands[] = ctools_ajax_command_callback('moncallback1', time());
    $commands[] = ctools_ajax_command_callback('moncallback2', time());
    $commands[] = ctools_ajax_command_callback('moncallback3', time());

    ctools_ajax_render($commands);

  }

}

Don't forget to create those JS functions in a JS file:

Drupal.CTools.AJAX.commands.callback.moncallback1 = function(data) {
    alert("Message1: " + data.data);
}

Drupal.CTools.AJAX.commands.callback.moncallback2 = function(data) {
    console.log("Message2: " + data.data);
}

Drupal.CTools.AJAX.commands.callback.moncallback3 = function(data) {
    alert("Message3: " + data.data);
}

Comments

pol’s picture

Status: Active » Needs review
StatusFileSize
new2.06 KB
pol’s picture

Issue summary: View changes

Adding code.

merlinofchaos’s picture

I don't understand the point. Why have this extra layer of callback business? Just create custom commands that do what you want?

merlinofchaos’s picture

I guess I should clarify.

What you're showing appears, to me, to be exactly what CTools already does, only you're wrapping it in a later that already does this. You're adding an extra layer of abstraction that doesn't, to me, make a lot of sense, unless there's something I"m missing.

pol’s picture

Yes that's it, custom commands that do anything with data replied from the server.

In my case, the server A needs to produce a XML and the client needs to send back the XML produced to another server B.

merlinofchaos’s picture

Re #4: What I'm saying is that you can already do this...without patching CTools.

pol’s picture

Status: Needs review » Closed (fixed)

Closing this as this is already possible to do in CTools.

We need to define our own function, then, create the JS accordingly.

Thanks for the fast reaction Merlin...

merlinofchaos’s picture

As an addendum, modal.inc and modal.js have an example of this.

FooZee’s picture

Just in case someone hit this page later on :)

modal.inc and modal.js are great examples of how to add your own ajax_commands .. however, I needed a little more-detailed tutorial on how to do this :) https://isovera.com/blog/create-custom-commands-drupal-7-ajax-framework was a great help

basically what you need to do is

  1. write the JS method that will actually handle that command say inside
    Druapl.mymodule.command_name= function(ajax, response, status){
    //your stuff here
    }
  2. Tell drupal that this is gonna be a new ajax command by attaching your new command to Drupal.ajax.prototype.commands like
      $(function() {
      Drupal.ajax.prototype.commands.command_name = Drupal.er.resultAppend;
      });
  3. you can now define a PHP function that returns an ajax command array like
    function mymodule_ajax_command_something ($arg1, $arg2, $arg3 ...) { //include as many arguments as u want :)
      return array(
      'command' => 'command_name', //the command name is the same as in Drupal.ajax.prototype.commands
      'arg1' => $arg1, //any arg u pass here will be available in the JS function you write under response.arg1 or response.arg2 or whatever
      ...
      );
    }
    
  4. don't forget to include your JS file before calling the ajax command ;) like what you would normally do with ctools_dismiss_modal()
FooZee’s picture

Issue summary: View changes

Adding more details.