Monday, January 14, 2013

Remembering User Choices

In my Chapter 2 of my ebook (SAS® Server Pages: Generating Dynamic Content) I show several examples of reporting functionality that use Stored Processes and SAS Server Pages on the SAS Portal where the user's choices are saved. As shown in the example screen shot, upon logging into the Portal and then selecting the reporting tab, the user's last report choice is remembered and submitted. The box on the left is a select tag (generated by the generateOptionTag utility macro) that uses the size option so multiple choices are displayed. This select tag is populated using the parms.report_list_view data set. The variable Report_Key is the value of the select tag and Report_Description is the label. Thus, remembering the user's choice is simply a matter of saving the value of Report_Key on the server.

The following simple data step saves the user's report choice so that it is available later in the same browser session; as well as the next time they log in (even if it is days later).

data profiles.&_metauser._report;
  Report_Key=&Report_Key;
run;

This code is included in the report driver macro so that whenever the user makes a choice, it is saved. The Stored Process Server provided macro variable _metauser is used to identify the user (note that if the SAS/IntrNet Application Dispatcher is being used, _rmtuser would be used instead of _metauser).

Using the following utility macro in the SAS Server Page that generates the UI allows the page to remember the user's last choice.:

%macro getReportKey;
 %local dsid rc;
 %let dsid=%sysfunc(open(profiles.&_metauser._report));
 %if &dsid=0 %then %return; /*no saved choices dataset*/
 %let rc=%sysfunc(fetch(&dsid));
 %if &rc=0 %then %sysfunc(getvarn(&dsid,1)); /* data set has a saved choice */
 %let dsid=%sysfunc(close(&dsid));
%mend getReportKey;

And then you only need to include code like what is shown below in the SAS Server Page:

%let Report_Key = %getReportKey;
.
.
.
%generateOptionTag
        (data = parms.report_list_view
        ,var = _report_key
        ,name = report_key
        ,selected = &report_key
        ,label = report_description
        ,otherOptions = size=30 onchange="submit();"
        )

That is really all there is to it.

Needless to say there are lots of variations and extensions of this technique:
  • This example has a dedicated data library (profiles) that has one data set for each user. A database or SAS/SHARE could be used so that the data is stored in a single data set with a row for each user.
  • Multiple data sets can be saved for each user if different kinds of data, or multiple values, need to be saved (in a future blog posting I will discuss the example in my book that uses multiple checkboxes, instead of a select tag). And, of course, there are any number of alternative data structures that could be used.
  • If the user id (_metauser) has special characters in it (e.g., /, \ or @), some siimple macro logic could be used to map it to a unique value that is a valid SAS name.
  • The macro could be paramaterized (I kept it simple for this example).
I have also used this technique with Web Report Studio using an Information Map as discussed in this example so that the user's choices are remembered for Web Report Studio reports. This can be particularly helpful when there are multiple reports and users don't want to have to reselect the report parameters for each report.