Monday, July 29, 2013

A SAS Server Page AJAX Template

In my last post I described a a SAS Server Page demo that used JQuery to provide both AJAX tools and a widget to produce tag clouds.

This is the first of several posts that will drill into the details of how it works. The topic for this post is a re-usable template that can be used for any number of reports: the ajaxContainer SAS Server Page (see figure 1).

Annotated ajaxContainer SAS Server Page
The contents of the SAS Server Page are described below with references to the numbers for each part of the output.

The first thing we do is ensure that the macro variables referenced/used in the template exist:
  • the formUI macro variable will resolve to the name of the SAS Server Page that contains the form fields so the user can make some selections (see 3 in figure 1). Note the use of %sysfunc with the coalesceC function to assign a default.
  • the footer macro variable will resolve to the name of the SAS Server Page that contains the HMTL to display at the bottom of the page (see 5 in figure 1). 
  • the messageText macro variable is assigned a value in the SAS Server Page referenced by formUI. This allows the text to be easily customized.
%global formUI footer messageText;
%let formUI = %sysfunc(coalesceC(&formUI,shoesForm.html));
%let footer = %sysfunc(coalesceC(&footer,hcsFooter.html));

Generate the HTML and in the head section, provide links to the hosted (by Google) JQuery tools. Using such links means that you need not download/install the basic JQuery environment script files to your server. But you do need to check for updates (e.g., the 1.10.1 and 1.10.3 in the URLs). Also note that by starting the URL with // instead of http or https allows will allow http vs. https to be used based on the base url.

<title>Sample AJAX Container</title>



Next is the JavaScript that controls the toggling of the UI/form. The ids showUI and hideUI reference a right arrow (show) and the left arrow (hide), discussed below that toggle the display of the form on/off. This technique allows the output to be seen on the same page as the form, while allowing to form to be hidden so as to maximize the screen real estate available to the output. 

Note that JavaScript could be included from another SAS Server Page using a macro variable similar to formUI and footer.

function toggleUI() {
 if (document.getElementById('showUI').style.display == 'none')
 { document.getElementById('showUI').style.display = 'block';
   document.getElementById('hideUI').style.display = 'none';
   document.getElementById('UI').style.display = 'none';
 { document.getElementById('UI').style.display = 'block';
   document.getElementById('hideUI').style.display = 'block';
   document.getElementById('showUI').style.display = 'none';


Just some HTML to define the text that appears at the top of the page. See 1 in figure 1. This could also have been parameterized like the footer, but I choose to show both techniques in this sample.

<div style="margin-bottom:5px; clear:both; height:15;

            background-color:#E4E4E4; color:#999999;
            font-family:Geneva, Arial, Helvetica, sans-serif;
            font-size:10px; font-style:italic;">
 <div style="float:left;">

  Learn more about these techniques in the SAS Press Book
   <a href=""
      style="text-decoration:none" target="_blank">
    SAS Server Pages and More: A Framework for Generating Dynamic Content
 <div style="float:right;">

   <a href=""
      style="text-decoration:none" target="_blank">
    SAS Server Page
    examples can be found on my
    <a href=""
       style="text-decoration:none" target="_blank">

The arrows that can be used to toggle the display of the form are defined next. See 2 in figure 1. The images are encoded as mentioned in my blog posting on base 64 encoded images.  This allows for the page to not have to worry about a path to the images directory and makes it more easily re-used and moved.

Note also the use of &streamDelim newline; to force PROC STREAM to issue a line feed. This helps ensure that linefeeds are not issued in the middle of some HTML text that perhaps should not be broken across lines.

&streamDelim newline;
<a id="showUI" href="JavaScript:toggleUI();"
   title="Show Selections"
   style="text-decoration:none; display:none;">
&streamDelim newline;

<img src="data:image/png;base64,R0lGODlhDAALAJEAACpVgbHB0Iuz2v///yH5BAEAAAMALAAAAAAMAAsAAAIhnB+nGrks3Gg0iOvs3TtpzjUgB0zAiV7lMwDCyp7sARsFADs="
&streamDelim newline;

<a id="hideUI" href="JavaScript:toggleUI();"
   title="Hide Selections"
   style="text-decoration:none; display:block;">
&streamDelim newline;

<img src="data:image/png;base64,R0lGODlhDAALAJEAALHB0CpVgYuz2v///yH5BAEAAAMALAAAAAAMAAsAAAIgnA2nB7ks3AOitpto3TtozgVDAIYGKQTqKp7po6hw/BQAOw=="

We next begin the div tag for the form/UI (note the id value is referenced above in the JavaScript that toggles the display on/off).

And we use the %include statement which causes PROC STREAM to do a server-side include of the form tag. By making the form a parameter to this template, we can use it to produce any number of reports. The included form generates the output seen in region 3 of figure 1.

<div id="UI" style="float:left;">
<form url="&_url" id="myForm">
&streamDelim;%include srvrpgs(&formUI);

Next is the JavaScript that leverages the JQuery AJAX framework to serialize and submit the form so the output can be displayed in the same page without having to refresh the entire page.

This only uses a few of the options available to the ajax function:
  • url: the url to display
  • success: the code to run if the URL is successfully run
  • note that there is an error/failure option as well. But being an optimist, and since this is a demo, I decided to not worry about that :-).
Note also that:
  • a please wait message is generated along with an image. I decided to not base 64 encode this as the encoded version is pretty long.
  • upon updating the output, the toggleUI JavaScript function is called to hide the form.
For the truly geeky and curious, there are lots of resources that you can find via a simple search that will how/why this works. For the rest of you, all I can say is trust me, it will work for you.

<script type="text/javascript">
    var frm = $('#myForm');
    frm.submit(function () {
    $("#region1").html('<div style="margin-left:50px">'

                     + '<h1>Processing . . . Please Wait . . . </h1>'
                     + '<img src="images/progress.gif""></div>');
    var theURL = "&_url?"+frm.serialize()+'&nocache='+Math.random();
            url: theURL,
            success: function (data) {
        return false;

Finally we define the region to contain the output. Note the id of region1 which is used in the AJAX code above. Note also that upon load the initial contents will be the text resulting from resolving the messageText macro variable (see 4 in figure 1). This variable is set in the code that is included when the formUI macro variable is resolved. As mentioned above, this allows for custom text for any given form.

<div id="region1" style="float:left; margin-left:10px;">

And last, a %include is used to include the footer text (see 5 in figure 1), followed by the /body and /html tags.
&streamDelim;%include srvrpgs(&footer);

I hope this all makes sense to you. If not, feel free to post questions about it.

In my next post I will discuss the two included files: shoesUI.HTML and hcsFooter.html.