Schneimi’s Dev Weblog


Update multiple fields with one ajax request response

Posted in Ajax,CakePHP by schneimi on October 27, 2007
Tags: , , ,

I searched for a possibility to update multiple fields with each ajax request made by a remoteTimer, but didn’t find any satisfying explanation on the web. To get that right, each field should get updated with the same response of a request.

So I had a look closer into the ajax helper and the prototype framework and came up with a little hack that suffice my needs and might be also helpful for others.

In the ajax helper (cake/libs/helpers/ajax.php) we first have to look into what happens when the options[update] parameter is set to an array with the different fields we want to update. That leads us to the ‘remoteFunction’ where following happens in that case:

$func = "new Ajax.Updater(document.createElement('div'),";

I have no clue what the creation of the div is really good for, but anyway we have to replace it with a JavaScript array holding the id’s of our fields:

$update = '[';

foreach($options['update'] as $option) {
  $update .= "'" . $option . "',";
}            

$update .= ']';                

$func = "new Ajax.Updater({$update},";

Now we must have a look into the prototype framework (app/webroot/js/prototype.js) and make sure the function Ajax.Updater can handle that array. The important function there is called updateContent:

Ajax.Updater = Class.create();

Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {

  [...]

  updateContent: function() {

    [...]

    if (receiver = $(receiver)) {
      if (this.options.insertion)
        new this.options.insertion(receiver, response);
      else
        receiver.update(response);
    }

    [...]
  }
});

Because the receiver is now our array, we must step through it and send a response to each of it:

Ajax.Updater = Class.create();

Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {

  [...]

  updateContent: function() {

    [...]

    if (receiver.constructor.toString().indexOf("Array") != -1) {
      for(var i = 0; i < receiver.length; i++) {
        if(r = $(receiver&#91;i&#93;)) {
      if (this.options.insertion)
        new this.options.insertion(r, response);
      else
        r.update(response);
    }
      }
    } else {
      if (receiver = $(receiver)) {
        if (this.options.insertion)
          new this.options.insertion(receiver, response);
        else
          receiver.update(response);
      }
    }

    &#91;...&#93;
  }
});&#91;/sourcecode&#93;
After checking if the receiver is actually an array, we step through it and send the response to every our fields.

Finished!

You can now use it like:
&#91;sourcecode language="php"&#93;
<?php echo $ajax->remoteTimer(array('url' => 'controller/action', 'update' => array('field1', 'field2', 'field3'), 'frequency' => '5')); ?>