Skip to content

June 22, 2009

18

Ajax/Prototype/JSON PeriodicalUpdater: A working example – log update on a background process (Part 1/2)

by Joe Kuan

PrototypeThis blog shows a real working Ajax.PeriodicalUpdater example (not just a hello world or non stop show timer). The example uses the PeriodicalUpdater to display a constantly updated log file from a background process running on the webserver. When the process finishes, the PeriodicalUpdater stops itself. Also a simple short PHP script is shown how to launch and check the status of a background process. 

HTML side

On the web front end, we setup three hyperlink buttons and two message boxes. One is to start a background process and the other two are two starting & stopping the log messages display.

<BODY>
<a href='' onclick='StartProc(); return false'>Start Process</a>
<a href='' onclick='ShowLog(true); return false'>Show Log</a>
<a href='' onclick='ShowLog(false); return false'>Don't Show Log</a>Status:<SPAN id=status></SPAN>
Log Messages: <DIV style='border:1px solid; width:40em; height:20em; font-size:12px; overflow:auto'                  id=log_messages></DIV>
</BODY>

So when the Start Process is clicked, it starts a background process on the webserver. The content of the log file appears inside the log_messages box when the Show Log link is clicked. The status box is to demonstrate the current status from the backend. So we can see what is actually going on inside the Ajax transactions.

Javascript (Ajax/Prototype/JSON) side

On the javascript side, the StartShowLog and StopShowLog are defined as:

/* Display message inside the status box based on the status value */
function DisplayMessage(t) {
   if (t.responseJSON) {
     var json = t.responseJSON;
     if (json['Status'] == 0) {
       Element.update($('status'), 'Info: ' + json['Message']);
     } else {
       Element.update($('status'), 'Error: ' + json['Message']);
     }
   } else {
     /* Update the whole content if it is not JSON */
     Element.update($('status'), t.responseText);
   }
}

/* Variable holding background process id */
var bgpid=null;

/* Start a background process and update the status box of the result */
function StartProc( ) {
  Element.update($('log_messages'), '');
  new Ajax.Request('start_proc.php', {
         method : 'get',
         parameters : 'bgpid=' + bgpid,
         evalJSON : 'force',
         onSuccess : function (t) {
             if (t.responseJSON &amp;amp;amp;&amp;amp;amp; t.responseJSON['Status'] == 0)
                bgpid = t.responseJSON['bgpid'];
             DisplayMessage(t);
         },
         onFailure : DisplayMessage
  });
}

/* ajax periodic updater */
var pu = null;

/* If show is true and pu is not instantiated, then create a PeriodicalUpdater
 * to inspect the process status and display the log messages
 * If show is true and pu is already instantiated, then restarts the PeriodicalUpdater
 * If show is false and pu is already instantiated, then stops the PeriodicalUpdater   */
function ShowLog(show) {
   if (show) {
     if (!pu)
       pu = new Ajax.PeriodicalUpdater(&amp;amp;quot;&amp;amp;quot;, &amp;amp;quot;get_proc_status.php&amp;amp;quot;, {
            method : 'get',
            frequency : 3,
            parameters : 'bgpid=' + bgpid,
            evalJSON : 'force',
            onSuccess : function(t) {
               if (t.responseJSON) {
                 /* Get the log message and display it */
                 new Ajax.Updater(&amp;amp;quot;log_messages&amp;amp;quot;, &amp;amp;quot;get_log_messages.php&amp;amp;quot;, {
                     onFailure : DisplayMessage
                     });
                 /* Bg process finishes or have error - stop the updater */
                 if (t.responseJSON['Running'] == 0 &amp;amp;amp;&amp;amp;amp; pu) {
                   pu.stop();
                 }
               }
               /* Display the current status of the background process */
               DisplayMessage(t);
               },
            onFailure : DisplayMessage
       });
    else {
       Element.update($('status'), 'Start showing log');
       pu.start( );
    }
 } else if (pu) {
   Element.update($('status'), 'Stop showing log');
   pu.stop();
 }
}

On the client side, when the Start button is clicked, the StartShowLog button checks whether the global variable pu has been assigned to a PeriodicalUpdater object. If not, creates an object and starts an Ajax call to get_proc_status.php to get the current background process status and displays log messages. If already assigned to an object, then simply calls the PeriodicalUpdater.start() method to restart the log message process. If the background process finishes (‘Running’ field inside JSON equals to 0, see get_proc_status.php), calls the PeriodicalUpdater object stop method. DisplayMessage basically inspects the content of responseText and sees whether it is composed of JSON. If so, then displays the messages according to the data defined in the result object.

Click here for Part 2.

At the time of writing, this example works on IE 8, Safari 4 and Firefox 3. Hope this helps.

I work for iTrinegy and here are my other Prototype blogs

Advertisements
18 Comments Post a comment
  1. Jul 6 2009

    Perfect!

    Reply
  2. jap
    May 9 2010

    i tried to get it working to zip directory in background but i cat get bgpid = t.responseJSON[‘bgpid’] set so when periodic updater start they say no process running and it’s on background.
    In return the status element return {“bgpid”:22640,”Status”:0,”Message”:”Process has been started 22640″} when process_star() and {“Status”:0,”Running”:0,”Message”:”Process is finished. {$bgpid}”} on display(show) link.
    Any idea why it’s not bgpid is not filled?

    JAP

    Reply
    • Joe Kuan
      May 9 2010

      Can you cut & paste the php code?

      Joe

      Reply
      • Joe Kuan
        May 9 2010

        You are using single quote instead of double quote in the php code.

        $result[‘Message’] = ‘Process is finished. {$bgpid}’;

    • Joe Kuan
      May 9 2010

      From what I notice from your code, I think the problem is the way you use parameters in Ajax.Request. It has to be an object of parameters.

      e.g method: ‘get’, parameters: { bgpid: bgpid}, ….

      Reply
  3. jap
    May 9 2010

    Joe, thank you for you time. But no change bgpid still null.

    bgpid = t.responseJSON['bgpid'];
    alert (bgpid);

    Reply
    • Joe Kuan
      May 9 2010

      What do you mean? All I can see your $result array in php hasn’t got $result[‘bgpid’] populated.

      require_once(“backup.inc.php”);
      $bgpid = $_GET[‘bgpid’];

      if (is_proc_running($bgpid)) {
      $result[‘Status’] = 0;
      $result[‘Running’] = 1;
      $result[‘Message’] = ‘Process is still running’;
      } else {
      $result[‘Status’] = 0;
      $result[‘Running’] = 0;
      $result[‘Message’] = ‘Process is finished. {$bgpid}’;
      }

      You are missing – “$result[‘bgpid’] = $bgpid;

      Reply
      • jap
        May 10 2010

        Joe thanks for help. I got this fixed. It was prototype.js 1.5.2 since I updated to 1.6.1 all working fine. Parameters in Ajax.Request and simple quote in $result[‘Message’] do not make any problem.
        It’s my fault for using outdated prototype. Your codes are perfect.

        Any idea how to make log_messages element scroll down as it’s filled?

        Regards, JAP

      • Joe Kuan
        May 10 2010

        Oh. Good. I was wondering something seriously wrong with my code.

        Try

        $(element).scrollTop = $(element).scrollHeight;

        Joe

  4. Ezra
    Nov 5 2010

    Thanks for posting this example. I just wanted to let you know that in the js example you have “&amp;amp;&amp;amp;” and other similar bits that don’t work.

    Reply
  5. kumar
    Jun 22 2011

    it’s not working

    Reply
  6. kumar
    Jun 22 2011

    give some downloading files

    Reply
    • Joe Kuan
      Jun 24 2011

      Sorry, work has been manic. Will try to do so, if I get some time.

      Reply
  7. Jul 17 2012

    What I have to install Apache modules?

    Reply
  8. Jul 18 2012

    Hey Joe, the script now works. Thanks
    But I run the script against without the refreshbutton an the show-log link show’s “Process is finished”, but /tmp/bgprog.sh still work’s.

    Reply
  9. Fotoğraf Yazıları
    Jul 7 2014

    To make this code which libraries should be included?

    ?

    Reply
    • Joe Kuan
      Aug 17 2014

      Sorry for the late reply. Been busy finishing a book.

      Unfortunately, this is such an old blog and I don’t keep this code update. Judging by the blog post day, I would guess 1.6.1.

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments

%d bloggers like this: