This is an example of how an ePub will reflow to different widths when viewed on various devices.

 

Chapter 5: Create a Custom User Interface for a Stored Process

5.1 The sasServerPage Stored Process

5.2 The runMacro Stored Process

5.3 Using the sasServerPage and runMacro Stored Processes to Create Prompt Pages

5.3.1 The stpHeader SAS Server Page

5.3.2 The stpTrailer SAS Server Page

5.3.3 The getDistinct Macro

5.3.4 The generateOptionTag Macro

5.4 Next Steps

Sections 5.1 and 5.2 of this chapter introduce two stored processes and a macro that are used in most of the examples in the rest of this chapter (and the book). They are included in the zip file described in the Appendix.

  • Stored Processes:

o sasServerPage

o runMacro

o an SPK file that you can use to import these two stored processes along with their parameters

  • Macros:

o sasServerPage.sas

Generating a custom user interface for a stored process (or a SAS/IntrNet Application Dispatcher program) can be accomplished by chaining two (or more) stored processes together. The first stored process generates the user interface where the user selects the desired options and uses the STREAM procedure with an input SAS Server Page to display the user interface. The second (or later) stored process in the chain generates the desired output. For the example presented here, we will use a generic stored process called runMacro that is used to run any macro that is available to a SAS session (for example, macros defined in a SAS autocall directory). This is a very powerful approach in a number of ways:

• If you have lots of reports and want to make them available from the SAS Stored Process Server, you need not create a distinct stored process for each one.

• Alternatively, if you have existing reports packaged as macros (or SAS programmers who are familiar with the SAS macro language), you can invoke the reports by using the runMacro stored process.

The runMacro stored process has at least one parameter—macroToRun, which specifies the name of the macro to run. (It might also have more parameters, depending on your environment.) Additional information about this approach can be found in the sasCommunity.org article The runMacro Stored Process, which includes links to numerous blog entries that highlight the various benefits of this approach.

These two stored processes can be registered in the same metadata folder, thus allowing for the stored process locations to reference each other using the &_metafolder macro variable created by the stored process server. The use of &_metafolder eliminates the need to hardcode stored process locations.

Note that the same technique can be used for SAS/IntrNet Application Dispatcher programs. The ability to generate a custom user interface for the stored process server enables you to develop user interfaces that might be preferred to the out-of-the-box user interfaces generated by the SAS BI prompting model. Because the SAS/IntrNet Application Dispatcher does not have a prompting model or metadata about the parameters for each program, the chaining technique is commonly used with the SAS/IntrNet Application Dispatcher.

The rest of this chapter focuses on the stored process server and the code for that environment. Almost identical code can be used with the SAS/IntrNet Application Dispatcher. The details specific to, along with the needed code changes for, the SAS/IntrNet Application Dispatcher are discussed in SAS/IntrNet SAS Server Page blog postings.

The following three sections describe these two stored processes and then show an example of how to use them, along with sample autocall macros and SAS Server Pages that you can customize and enhance for your application environment:

The sasServerPage Stored Process

The runMacro Stored Process

Using the sasServerPage and runMacro Stored Processes to Create Prompt Pages

5.1 The sasServerPage Stored Process

The sasServerPage stored process simply calls a macro called sasServerPage. This allows the macro to be called from other stored processes or programs as needed:

*ProcessBody;
 
%sasServerPage(fileref = &srvrpgs       /* SAS Server Pages aggregate fileref */
              ,page = &page            /* name of the SAS Server Page to use */
              ,quoting = &quoting      /* quoting option for PROC STREAM */
              ,asis = &asis            /* asis option for PROC STREAM */
              ,noAbSSCmt = &noAbSSCmt  /* noAbsSCmt option for PROC STREAM */
              )

The specified parameters to the macro are also stored process parameters. Default values are assigned in the definition of the stored process for each parameter. These values correspond to PROC STREAM's parameters:

• The fileref parameter specifies an assigned fileref for an aggregate location (a directory or set of concatenated directories) where the input SAS Server Pages are stored.

• The page parameter specifies the name of the SAS Server Page to be processed.

• The quoting parameter specifies the handling of single and double quotation marks (the value to be used for the PROC STREAM quoting parameter).

• The asis parameter is either blank or has the value &asis (corresponding to the like-named PROC STREAM parameter).

• The noAbsSSCmt parameter is either blank or has the value &noAbsSSCmt (corresponding to the like-named PROC STREAM parameter).

The sasServerPage macro source follows:

%macro sasServerPage
       (fileref = srvrpgs               /* fileref for server page locations   */
       ,page =                         /* list of server pages               */
       ,defaultExtension = html        /* default extension if not provided  */
       ,outfile = _webout               /* destination to write output to     */
       ,mod =                          /* mod if appending to &outfile        */
       ,quoting = both                 /* single/double quote handling       */
       ,asis =                         /* attempt to preserve columns/ASIS   */
       ,noAbSSCmt =                    /* include slash-star comments        */
       );

information_icon.jpg

 %local quot amp apos lt gt nbsp copy reg;
 %let quot = "
 %let amp = &
 %let apol = '
 %let lt = <
 %let gt = >
 %let nbsp =  
 %let copy = ©
 %let reg = ®

information_icon.jpg

 %if %scan(&page,2,.) = %then %let page = &page..&defaultExtension;
								
							

information_icon.jpg

 proc stream outfile = &outfile &mod &asis &noAbSSCmt
             %if %length(&quoting) > 0 %then quoting=&quoting;
 ;
   BEGIN
   %include &fileref(&page);
 ;;;;
 run;

%mend sasServerPage;

Note that the macro has three additional parameters not defined as parameters for the stored process because they rarely, if ever, need to be modified from their default values when the macro is run from the stored process. They are likely to be used when the sasServerPage macro is called directly from another SAS program:

• the output location, outfile, which for a stored process is almost always _webout.

• the mod, which in the stored process (and SAS/IntrNet Application Dispatcher) environment is always enabled.

• the defaultExtension, which again is almost always html. (Note that in a stored process environment the default extension is not used if the extension is included in the value of the page parameter.)

5.2 The runMacro Stored Process

A simple version of a runMacro stored process source follows. The name of the macro to run is passed as an input parameter.

information_icon.jpg

*ProcessBody;
 
%stpbegin;
 
%put NOTE: Execute macro &macroToRun..;
%&macroToRun
 
%stpend;

5.3 Using the sasServerPage and runMacro Stored Processes to Create Prompt Pages

In section 2.2.1, an example was shown where the user was prompted to select the products to be included in a report. That sample invoked the selectedProductsReport macro, which subset the data and ran a PROC REPORT step on the product values selected by the user.

In addition to the stored process and macros discussed in section 5.1 and 5.2, the programs and SAS Server Pages discussed in this section are included in the zip file described in the Appendix:

  • SAS Server Pages:

o stpProductSelectTag.html

o stpProductCheckboxes.html

o stpHeader.html

o stpTrailer.html

  • Macros:

o sasServerPage.sas

o getDistinct.sas

o generateOptionTag.sas

Recall that the example shown in section 2.2.1 included a number of desirable features:

• the ability to show the output in the same window as the user interface where the user specified which products to include in the report

• the ability to show or hide the selection form so as to maximize the amount of screen real estate for the output, while still allowing for easy access to the selection user interface for making changes

• the ability to show a processing image to alert the user that the report is running—something that is important for reports that don't return results immediately

Instead of duplicating the HTML (and JavaScript) that provides this functionality in each and every SAS Server Page that is used to prompt the user for parameters, the following examples leverage the %INCLUDE facility of PROC STREAM. That facility allows for the development of a standard structure for your reports and user interfaces without requiring duplication of code. Storing common code in an external file and using the %INCLUDE statement to include the output created by PROC STREAM should be considered a best practice. Such SAS Server Pages contain at least three sections:

• The first section simply uses %INCLUDE to define a standard page header.

• The next part is the specific HTML, including macro variable references and macros, to generate the user interface for the subject report accessed as a stored process (in this case the selectedProductsReport macro run by the runMacro stored process).

• The last section simply uses %INCLUDE to define a standard page trailer.

This technique has broad applicability as the header or trailer section can also be used to display application or corporate logos, including confidentiality or copyright text, and so on.

Figure 5.1: Video of Two Alternative User Interfaces

 

The following two SAS Server Pages generate the user interfaces shown in the video in Figure 5.1. The first one uses a select tag and the second one uses check boxes to prompt users to specify the products they want to include.

information_icon.jpg

%global pageTitle macroToRun _debug;
%let pageTitle=Products Select Tag;
%let macroTorun=selectedProductsReport;

information_icon.jpg

&streamDelim;%include &srvrpgs(stpHeader.html);

information_icon.jpg

%let rc = %sysfunc(dosubl(%nrbquote(
%getDistinct(data=sashelp.shoes
            ,vars=product
            ,out=productList)
)));

information_icon.jpg

%generateOptionTag(data=productList
                  ,var=product
                  ,otherOptions=multiple size=&sqlobs)

information_icon.jpg

 <p><input type="submit" value="Run Report">
								
							

information_icon.jpg

&streamDelim;%include &srvrpgs(stpTrailer.html);
								
							

The sample header and trailer SAS Server Pages, as well as the getDistinct and generateOptionTag macros, are described in the following subsections.

Check boxes can be simpler for the user (they don't need to know about using the CNTL key) if multiple selections are allowed. The following SAS Server Page (output shown in Figure 5.2) demonstrates this technique to create a set of check box fields. It uses the same standard header and trailer server pages as described previously, thus allowing the page to focus on just the functionality needed for the specific user interface components for the desired report.

Figure 5.2: A Prompt Page Using Check Boxes

Image891.PNG

information_icon.jpg

%global pageTitle macroToRun _debug;
%let pageTitle=Products Checkboxes;
%let macroTorun=selectedProductsReport;

information_icon.jpg

&streamDelim;%include &srvrpgs(stpHeader.html);

information_icon.jpg

%let rc = %sysfunc(dosubl(%nrbquote(
 proc sql noprint;
 select distinct cats(‘&streamDelim newline;<input type="checkbox" name="product" value="‘,strip(product),’">’
                      ,strip(product)
                     )
 into:checkBoxes separated by ‘<br>’
 from sashelp.shoes;
 quit;
)));
&checkboxes

information_icon.jpg

<p><input type="submit" value="Run Report">

information_icon.jpg

&streamDelim;%include &srvrpgs(stpTrailer.html);

Another desirable feature shown in Section 2.2 is the ability to save the user's choices (also known as Saving State). Those details are not included here. However, one method of doing that is described in these blog postings on saving user choices.

5.3.1 The stpHeader SAS Server Page

The stpHeader SAS Server page is an example of packaging reusable functionality to create custom user interfaces for stored processes. It illustrates how using PROC STREAM can enable you to create sophisticated custom user interfaces, and it packages the following capabilities:

• displaying the user interface side by side in a single window with the output from the submitted stored process

• toggling the user interface display on and off, thus freeing up screen real estate for the output of the stored process

• displaying a message and an image that highlights to the user that the stored process has been submitted and is running

• including standard text at the bottom of the page

The following source can be easily changed and customized in order to suit the needs of your stored processes, thus enabling you to create any number of alternative user interfaces. A basic understanding of HTML and JavaScript by the reader is assumed.

information_icon.jpg

%global pageTitle macroToRun _debug;
%let _debug = %sysfunc(coalesceC(&_debug,0));
spacer_icon.jpg
<html>
<head>

information_icon.jpg

<script> 
function toggleForm() {
 if (document.getElementById(‘showForm’).style.display == ‘none’)
 { document.getElementById(‘showForm’).style.display = ‘block’;
   document.getElementById(‘hideForm’).style.display = ‘none’;
   document.getElementById(‘form’).style.display = ‘none’;
 }
 else
 { document.getElementById(‘form’).style.display = ‘block’;
   document.getElementById(‘hideForm’).style.display = ‘block’;
   document.getElementById(‘showForm’).style.display = ‘none’;
 }
}

information_icon.jpg

function processing() {
 window.frames(‘results’).document.body.innerHTML =
   ‘<center>’
 + ‘<b><i>Please Wait</i></b>’
 + ‘<p><img src="/SASStoredProcess/images/progress.gif">’

information_icon.jpg

 ;
 toggleForm();
}
</script>
spacer_icon.jpg
<title&pagetitle</title>
</head>
<body>

information_icon.jpg

<a id="showForm"
   href="JavaScript:toggleForm();"
   title="Show Selections"
   style="text-decoration:none; display:none;">
<img src="/SASStoredProcess/images/arrow-right-default.gif"
     border="0">
</a>

information_icon.jpg

<a id="hideForm"
   href="JavaScript:toggleForm();"
   title="Hide Selections"
   style="text-decoration:none; display:block;">
<img src="/SASStoredProcess/images/arrow-left-default.gif"
     border="0">
</a>

information_icon.jpg

<table style="width:100%; height:100%;">

information_icon.jpg

<tr>
<td id="form"
    style="float:left; display:block; vertical-align:top">
<form action="&_url"
      target="results"
      onSubmit="processing();">
<input type="hidden"
       name="_program"

information_icon.jpg

       value="&_metafolder.runMacro">
<input type="hidden"
       name="macroToRun"
       value="&macroTorun">

information_icon.jpg

<input type="hidden"
       name="_debug"
       value="&_debug">

This page uses images provided by SAS for the right and left arrows. If other images are desired, the above img tags can be replaced with other images. Alternatively, an image can be displayed using the Base 64 URI Data Scheme. For example, the right arrow above could be replaced with the following text:

<img src=
"data:image/png;base64,R0lGODlhDAALAJEAACpVgbHB0Iuz2v///yH5BAEAAAMALAAAAAAMAAsAAAIhnB+nGrks3Gg0iOvs3TtpzjUgB0zAiV7lMwDCyp7sARsFADs=" border="0">

The left arrow could be replaced with the following text:

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

Using this scheme allows for the image source to be included as text in the SAS Server Page. In addition, referencing utility images such as the arrows in this way also allows for such SAS Server Pages to be used without concern for the location of the directory or folder where the images are located. This can be advantageous for output that is not created by the stored process server or for the use of images that are not provided by SAS. The menuPanel SAS Server Page discussed in Chapter 8 uses this Base 64 approach for images. A number of Web sites can be used to convert an image to its Base 64 representation.

5.3.2 The stpTrailer SAS Server Page

The stpTrailer SAS Server Page is included by the calling SAS Server Page to close the form and to define the display area for the stored process output. Like the stpHeader SAS Server page, it can be easily changed and customized in order to suit the needs of your stored processes.

information_icon.jpg

</form>
</td>
<td style="overflow-x:hidden; display:block; vertical-align:top">>

information_icon.jpg

<iframe name="results"
        width="100%"
        height="100%"
        frameborder="0">
</iframe>
spacer_icon.jpg
</td>
</tr>

information_icon.jpg

<tr>
<td colspan="2" style="height:15; background-color:#E4E4E4; color:#999999; font-family:Geneva, Arial, Helvetica, sans-serif; font-size:10px; font-style:italic;">
<div style="float:left;">
<a href="http://www.sascommunity.org/wiki/SAS%C2%AE_Server_Pages:_Generating_Dynamic_Content"
 style="text-decoration:none" target="_blank">
SAS&reg; Server Pages: Generating Dynamic Content
</a>
</div>
<div style="float:right;">
<a href="http://www.hcsbi.com"
   style="text-decoration:none" target="_blank">
Henderson Consulting Services
</a>
</div>
</td>
</tr>
spacer_icon.jpg
</table>
</html>

5.3.3 The getDistinct Macro

The getDistinct macro is an example of a simple utility macro that can be stored in a macro autocall directory and used whenever a list of distinct values is needed. It has the following parameters:

• The data parameter specifies the name of the data set from which the distinct values are to be obtained.

• The vars parameter specifies the variable(s) for which the distinct values (or distinct combinations if multiple variables are listed) are desired. A distinct list of combinations of values could be used, for example, when creating cascading select tags.

• The out parameter specifies the name of the output data set containing the default values. The DATAn convention is the default.

%macro getDistinct
     (data =          /* name of data set */
     ,vars =          /* list of variables for the select distinct */
     ,out = _data_    /* output data set name */
     );
 /* convert var list to csv for use in SQL */
 %let vars = %sysfunc(compbl(&vars));
 %let vars = %sysfunc(translate(&vars,%str(,),%str( )));
 proc sql noprint;
  create table &out as 
  select distinct &vars
  from &data;
 quit;
%mend getDistinct;

5.3.4 The generateOptionTag Macro

The generateOptionTag macro reads the rows in the input data set using the data access functions (OPEN, CLOSE, FETCH, GETVARC, GETVARN) that are executed using the %SYSFUNC macro.

The macro has the following parameters:

• The data parameter specifies the name of the data set to use to populate the select tag.

• The var parameter specifies the name of the variable that provides the value (that is, that value submitted to the server when the form is submitted) for the option tag.

• The label parameter specifies the name of the variable that provides the label (the visible text) for the option tag. If not provided, it defaults to the value of the var VAR parameter.

• The name parameter specifies the name of the select tag form field. If not provided, it defaults to the value of the var parameter.

• The where parameter specifies an optional WHERE clause used to subset the data set specified in the data parameter.

• The selected parameter specifies a currently selected value (only one value can be provided; the macro does not support multiple selections). Select tags that allow for multiple selections are best handled by a dual list box selector. A sample SAS Server Page implementation of a dual list box selector is described in this blog posting.

• The blank parameter, when given a non-blank value, specifies an additional option tag that is listed as the first option. This parameter is typically used to specify a value such as "--Please Select an XXXX--."

• The blankValue parameter specifies an optional value to use for the option tag generated by the blank BLANK parameter.

• The otherOptions parameter specifies a parameter that can be used to pass any other text to be used in the select tag. This parameter is typically used to specify onSubmit, style, and so on.

%macro generateOptionTag
      (data=             /* data set used to populate the pull-down list */
      ,var=              /* variable whose value is the option value */
      ,label=            /* variable whose value is the display value */
      ,name=             /* name for the SELECT tag */
      ,where=            /* optional WHERE clause to subset the data */
      ,selected=         /* the value to highlight as selected */
      ,blank=            /* used to insert an initial entry/label */
      ,blankValue=%str() /* the option value if blank= is specified */
      ,otherOptions=     /* other text to be included in the SELECT tag */
      );
spacer_icon.jpg
 %local dsid varnum varlabel value display vartype1 vartype2 thisSelected i;

information_icon.jpg

 %if %length(&where) ne 0
     %then %let where = (where = (&where));
spacer_icon.jpg
 %if %length(&name) = 0
     %then %let name = &var;

information_icon.jpg

 %let dsid = %sysfunc(open(&data&where));
 %let varnum = %sysfunc(varnum(&dsid,&var));
 %if %length(&label) gt 0
     %then %let varlabel = %sysfunc(varnum(&dsid,&label));
 %else %let varlabel = &varnum;
 %let vartype1 = %sysfunc(vartype(&dsid,&varnum));
 %let vartype2 = %sysfunc(vartype(&dsid,&varlabel));

information_icon.jpg

&streamDelim newline;
<select name = "&name" &otherOptions>
 %if %length(&blank) ne 0
     %then %str(&streamDelim newline;
                <option value="&blankValue">&blank

information_icon.jpg

               );

information_icon.jpg

 %do %while(%sysfunc(fetch(&dsid))=0);

information_icon.jpg

     %let value = %qsysfunc(getvar&vartype1(&dsid,&varnum));
     %let display = %qsysfunc(getvar&vartype2(&dsid,&varlabel));
     %if %bquote(&value)=%bquote(&selected)
         %then %let thisSelected = selected;
     %else %let thisSelected =;

information_icon.jpg

&streamDelim newline;<option &value &thisSelected>%qtrim(&display)
 %end;
&streamDelim newline;</select>

information_icon.jpg

 %let dsid = %sysfunc(close(&dsid));
spacer_icon.jpg
%mend generateOptionTag;

5.4 Next Steps

Additional information about creating User Interfaces with SAS Server Pages and PROC STREAM can be found on the author's blog. Please consult those blog entries for additional examples as well as to discuss the examples presented in this chapter.