@AhmedAl_Attar Still I get the same error when I tried to use Filename statement per your instruction. I kept the following line before proc steam.
Filename sample '/home/babloo/test/_webout';
Even I tried this without any path,
Filename sample '_webout';
Am I missing something?
Typical SAS Filename Statement is composed as follows
FILENAME <FileReference> <Location | TEMP>;
Try this
Filename _webout TEMP; /* Will place the file in the same location as your SAS WORK library */
/* or */
Filename _webout '~/mywebout.html'; /* Explicitly specifying physical output file name */
Hope this helps
@AhmedAl_Attar thanks but still the other error persists. ERROR 180-322: Statement is not valid or it is used out of proper order.
Log:
81 Filename _webout TEMP; 82 83 proc stream outfile=_webout quoting=both; 84 BEGIN 85 <html> 86 <body><title>Select Products</title><body> 87 %let rc =%sysfunc(dosubl( 88 proc sql noprint; 89 Figure 8. First Attempt to Include SAS Code in a SAS Server Page 90 11 91 select distinct 92 '<input type="checkbox" name="product" value="' 93 ||strip(product) 94 ||'">' ERROR 180-322: Statement is not valid or it is used out of proper order. NOTE: PROC SQL set option NOEXEC and will continue to check the syntax of statements.
I think when you copied the code lines from the paper, some additional non SAS lines where included!
Figure 8. First Attempt to Include SAS Code in a SAS Server Page 11
I ran this code without any issues and generated the desired result.
Filename _webout TEMP;
%let rc = %sysfunc(dosubl(
SAS Code - potentially spanning multiple lines
));
proc stream outfile=_webout quoting=both;
BEGIN
<html>
<body><title>Select Products</title><body>
%let rc =%sysfunc(dosubl(
proc sql noprint;
select distinct
'<input type="checkbox" name="product" value="'
||strip(product)
||'">'
||strip(product)
into:checkboxes separated by '<br>'
from sashelp.shoes;
quit;
)); /* End both the DOSUBL function call and the
%SYSFUNC macro function */
&checkboxes
</body>
</html>
;;;;
run;
<!DOCTYPE html> <html> <head> <meta name="generator" content= "HTML Tidy for HTML5 for Windows version 5.0.0.RC1"> <title>Select Products</title> </head> <body> <form><input type="checkbox" name="product" value="Boot">Boot<br> <input type="checkbox" name="product" value="Men's Casual">Men's Casual<br> <input type="checkbox" name="product" value="Men's Dress">Men's Dress<br> <input type="checkbox" name="product" value="Sandal">Sandal<br> <input type="checkbox" name="product" value="Slipper">Slipper<br> <input type="checkbox" name="product" value="Sport Shoe">Sport Shoe<br> <input type="checkbox" name="product" value= "Women's Casual">Women's Casual<br> <input type="checkbox" name="product" value= "Women's Dress">Women's Dress</form> </body> </html>
@AhmedAl_Attar How did you got the HTML code which you showed in your post? I executed the SAS code in SAS Studio based on your instructions and there is no error in the log now. However I could not see the result. May I know where to check the result?
When you use the 'TEMP' keyword for in your Filename statement, SAS creates a special physical file under the WORK Library path called something like (#LN000XX) XX is a number.
You can use this statement to find your current WORK Library physical path
%put %sysfunc(pathname(WORK));
You'll need to look there or a level above it for the #LN000XX file 😉, Once you open it (#LN000XX) using a Browser, you should be able to see the Check Boxes.
PS. I used UltraEdit to reformat/tidy the generated HTML as well as Apply "Browser View" to show the Check Boxes.
@Babloo wrote:
For me WORK path is /sastmp/... I don't know how to go to this path. I
will check with SAS admin on this.
In the same location we can see the generated HTML which you shown in your
post? If not, where to see it?
I know I'm asking many questions and I'm sorry for that.
If you are using SAS/Studio to test the HTML generation then you can use one of its features to let you DOWNLOAD the file as soon as it is generated. Basically write the file using the fileref _DATAOUT. And then also set the macro variables _dataout_name and _dataout_mime_type
I am still not sure if you need to use the fancy Viya features for web interfacing. You mentioned that the page is STATIC, but it needs information from a SAS dataset to generate the selection lists. If the page is truly static and the information in the SAS dataset is reasonably stable then you can still get away with just making a SAS program that writes the HTML file. You will just need to re-generate the HTML every time you make changes to the SAS dataset.
Typically the WORK Library physical path would look something like this
/<SomePath>/SAS_workxxxxxxxxxxxx_<Fully Quqlified Server Name>/
In both SAS Studio 5.2 / SAS StudioV your SAS Viya Admin may have only allowed/configured certain folders that can be exposed via the Explore Navigation pane.
Therefore I would contact your SAS Viya Admin and request he/she download that file for you. To make this process more clear, try to assign the File reference as follows
FILENAME _WEBOUT "%sysfunc(pathname(WORK))/_webout.html";
This way you'll have a physical file name he/she can look for under the /sastmp/ folder
Hope this helps
@AhmedAl_Attar I added this line Filename _webout "/ifrs/test/_webout.html"; on yesterday and it was working fine and I could see the html file in the mentioned location. When I executed the same code today, it ended up with error as shown below. Even I removed the HTML file from the location where it was created on yesterday and even I changed the path in Filename statement as well but still the same error. Any help?
Filename _webout "/ifrs/test/_webout.html"; ERROR: At least one file associated with fileref _WEBOUT is still in use. ERROR: Error in the FILENAME statement.
Where you running this code?
If the regular SAS Studio program entry causing the issue, this could mean your yesterday's SAS process ID/Session never terminated properly!?
You can
$ ps -ef | grep <PutYourUserIDHere>
Note: The above Linux command should show you what Linux Processes you have running under your Network ID, look for anything from last night and try to kill it using the following command
$ kill -9 <PID>
Hope this helps
The way I see it, the library you reference in
data-library=
has to be defined and assigned in SAS already, either through metadata or in the autoexec file(s).
@AhmedAl_Attar I came across the following articles today and I observed that we can use a rest API call to retrieve the distinct values of a column. from a SAS dataset. 'Proc http' does this it seems. I can try this later.
Creating JES Prompts and Output Using the Viya Reports API - SAS Support Communities
Executing a JES Job Using JavaScript - SAS Support Communities
Now my question is how to embed (or add) the HTML code which I already wrote with the Proc http which I'm going to write?
Hi @Babloo,
Few of points to keep in mind, when you analyze what's this article "Creating JES Prompts and Output Using the Viya Reports API" is doing
// make request to reports API var xmlhttp = new XMLHttpRequest(); var url = "/reports/reports?limit=10&sortBy=creationTimeStamp:descending"; xmlhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var myArr = JSON.parse(this.responseText); createSelection(myArr); } else { document.getElementById("reportList").innerHTML = "Status: " + this.status; } }
// convert response into a dropdown function createSelection(rList) { var prompt = '<select name="reportSelect">'; var i; for(i = 0; i < rList['items'].length; i++) { prompt += '<OPTION VALUE="' + rList['items'][i].id + '">' + rList['items'][i].name; } prompt += '</select>' document.getElementById("reportList").innerHTML = prompt; }
This means, you'll need to have an equivalent SAS Program/JES Job on the server, similar to the Viya Report API, that you can pass it a Data Set name, and Column name, and it returns JSON response, so your JavaScript function could transform it into a HTML <select> <option> </select> Tags
I would guess the steps for that would be
1. Create new Viya Job that takes two parameters (dsName, ColName), and it returns JSON
2. Create new Viya Job that follows the steps in this article "Creating JES Prompts and Output Using the Viya Reports API", where it's using AJAX (xmlhttp = new XMLHttpRequest();), and calls your job that you created in Step 1 via (var url = "/<jobLocation>/<JobName>?dsName=sashelp.cars&colName=models";)
3. You create custom JavaScript Function similar to "function createSelection(rList)" but it may take three parameters instead of 1 (rList, ElementId,SelName)
Hope this helps
Hi @Babloo
Here is how I was able to get this running in our Viya 3.5 now 😊
The Job was saved under the Public Folder (/Public/getDsColValues). Here is it's SAS code.
/* Generate unique list of values */
Proc summary data=&s_dsName NWAY missing;
class &s_colName;
output out=work._unique(drop=_type_);
run;
proc json out=_webout pretty nosastags;
export work._unique;
run;
<html>
<head>
<link rel="stylesheet" href="/SASJobExecution/theme">
</head>
<body>
<h1 class="jobexec_sample_name">Creating JES Prompts and Output Using SAS Data sets</h1>
<p>
The prompts below contains items pulled dynamically from SAS data sets.
<br><br>
To view data set records, make a seletion and press 'submit'
</p>
<p>
<form action="javascript:submitForm();">
<!-- Define Dropdown/Select place holders -->
<div id="yearList"></div>
</nbsp>
<div id="stateList"></div>
</nbsp>
</nbsp>
<p></p>
<input type="submit">
</form>
<center>
<div id="JobResults"></div>
</center>
</body>
<script>
// CREATE AN XMLHttpRequest OBJECT, WITH POST METHOD.
var formData = new FormData();
// This is my SAS Job that returns JSON Objects Array of unique values list from a SAS Data set.
formData.append("_program", "/Public/getDsColValues");
formData.append("_action", "execute");
formData.append('_csrf', "$CSRF$");
formData.append('s_dsName', "sashelp.prdsal2"); // SAS Data set specified for the s_dsName parameter
formData.append('s_colName', "year"); // Year column specified for the s_colName parameter
formData.append("_output_type", "json");
// Declare Ajax request object for the YearList
var xhr = new XMLHttpRequest();
xhr.addEventListener("error", function (event) {
alert("Something went wrong.");
});
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
// Pass Parsed JSON DATA, and other info to the custom function
createSelection(JSON.parse(this.responseText),'year','YEAR',1);
}
else {
document.getElementById("yearList").innerHTML = "Status: " + this.status;
}
}
};
// Declare Ajax request object for the StateList
var xhr2 = new XMLHttpRequest();
xhr2.addEventListener("error", function (event) {
alert("Something went wrong.");
});
xhr2.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
// Pass Parsed JSON DATA, and other info
createSelection(JSON.parse(this.responseText),'state','STATE',5);
}
else {
document.getElementById("stateList").innerHTML = "Status: " + this.status;
}
}
};
// Submit the request and get Year data elements from SAS data set
xhr.open("post", "/SASJobExecution/");
xhr.send(formData);
// Submit the request and get State data elements from SAS data set
xhr2.open("post", "/SASJobExecution/");
formData.set('s_colName', "state"); // Reuse the same formData object, but just change the value of the s_colName parameter
xhr2.send(formData);
// Display a temporary message in the DIV
document.getElementById("yearList").innerHTML = "Please wait ... ";
document.getElementById("stateList").innerHTML = "Please wait ... ";
//Declare a Function to convert JSON response into a Dropdown selection widget
function createSelection(rList,prefix,name,size = 1) {
var listName = prefix + 'List';
var prompt = '<select name="' + prefix + 'Select" size="' + size + '">';
var i;
//alert(JSON.stringify(rList));
for(i = 0; i < rList.length; i++) {
prompt += '<OPTION VALUE="' + rList[i][name] + '">' + rList[i][name] + ' :' + rList[i]._FREQ_ + '</option>';
}
prompt += '</select>'
document.getElementById(listName).innerHTML = prompt;
}
function submitForm() {
var formData = new FormData();
formData.append("yearParm", document.querySelector('[name="yearSelect"]').value);
formData.append("stateParm", document.querySelector('[name="stateSelect"]').value);
formData.append("_program", "$PROGRAM$");
formData.append("_action", "execute");
formData.append('_csrf', "$CSRF$");
var request = new XMLHttpRequest();
request.addEventListener("error", function (event) {
alert("Something went wrong.");
});
request.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
document.getElementById("JobResults").innerHTML = this.responseText;
}
else {
document.getElementById("JobResults").innerHTML = "Status: " + this.status;
}
}
};
request.open("post", "/SASJobExecution/");
request.send(formData);
// Display a temporary message in the DIV
document.getElementById("JobResults").innerHTML = "Please wait ... ";
}
</script>
</html>
I stopped here once I was able to populate my HTML Select/DropDown widgets from SAS, after all, this is just Prove of Concept 😉
I hope this gets your closer to your goal.
But I'll just repeat my advice again, for SAS Viya 3.5 stick with the TASK Prompts, out of the box, they are probably a lot more feature rich compared to what you would spend time to build using JavaScript/HTML/CSS combination.
Good luck,
Ahmed
Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.