Pages

Sunday, 20 September 2020

Fetch browser data into Component Buffer

It's Hidden in the Field.
Photo by Patrick Mueller

I had to remind myself recently of how to solve a particular problem that I first solved probably over 15 years ago (probably in version 8.01 of PeopleTools).  

If I use JavaScript to fetch some data from the browser then how do I get this new local data back into the component processor and make it available to PeopleCode?

This might be useful to someone out there so here's how it's done.  I'm going super simple with this example so that hopefully the concepts are clear.  

Let's assume we have a Page with a single Field - DESCR (Description).  We're going to use JavaScript to fetch the Operating System of the local machine.  A button will then pass that back to the Component Processor and in the FieldChange event we'll display the Operating System name in the DESCR field.




(1) First I need to get my Javascript into the page.  There are many ways to do this but for this example I'm just going to add an HTML area to the page and set it's value to be my JavaScript during the PageActivate of the Page.

This is my JavaScript to get the Operating System.

<script>

// Get the Operating System name from the appVersion property*/
var OSName="Unknown Operating System"; 
if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows"; 
if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS"; 
if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux"; 

// Set the hidden field on page using the PageField Name
document.getElementById("MY_DESCR1").value = OSName;

// The hidden field can also be referenced by using RECORD_FIELDNAME
// document.getElementById("GRS_TEST_WRK_DESCR1").value = OSName;

</script>
And the code to inject this into my Page at runtime.

NOTE: When the HTMLAREA value is set in PageActivate the JavasScript at this stage has not been rendered in the browser and therefore it hasn't executed yet.  This is important to note as anything which the JavaScript does on the page at render time will not be available to the Component Processor until the next rountrip.

ALSO NOTE:  It might matter where you put your JavaScript on the page.  HTML pages do not load all at once and so HTML elements that your JavaScript reference may not have rendered at the time they execute and may not be available.  For the purposes of this simple test we can get away with adding the JavaScript to the end of the Page but a much more thorough discussion on this can be found here  https://www.kirupa.com/html5/running_your_code_at_the_right_time.htm

(2) Pass the JavaScript variable to the local PeopleSoft Page.  Fields on a PeopleSoft Page are located inside the <FORM> object so that when the next HTTP POST event (or roundtrip) occurs the collection of Field objects or (HTML INPUT elements) in the form are posted (sent) back to the web server and then to the application server to be made available in the Component Buffer.

Normally we use data entry elements on the Page to capture human input but in this instance our JavasScript is doing the inputting.  However, we don't necessarily want our Operating System name to be visible on the Page so we add a hidden Field on the Page and set the value of this using JavaScript. In this example the hidden Field name is DESCR1 and we're going to make it invisible.

Setting the Page Field Invisible property not only makes the field hidden from human view but the way in which PeopleSoft does this (quite rightly) is to not include the Field in the HTML page response thus making it invisible to JavaScript too.  We solve this problem by also setting the Generate in HTML property and Modifiable by Javascript* property.


NOTE: If you don't set the Modifiable by Javascript property then you'll get this error.

This is because the HTML element for the Field will be present in the HTML but is not permitted to be changed. Actually, JavaScript will modify the Field value but the next roundtrip will catch this illegal operation and throw the error.  This feature might be useful if you wanted to apply some special HTML/CSS wizardry to  Field data but didn't want to display the default PeopleSoft styled Field.

One other Page Field property is useful to set on our hidden field and that's the Page Field Name.  All Page Fields can be referenced by the RECORD_FIELDNAME and this is set as the Element ID.  However, as we all know, it's possible to have the same Field appear multiple times on a page and having a method of uniquely identifying a specific instance of a Field is useful and sometimes essential.  



The line of JavaScript which sets the hidden field is this one:
/*Set the hidden field on page*/
document.getElementById("MY_DESCR1").value = OSName;
or, alternatively using the RECORD_FIELDNAME.  
// The hidden field can also be referenced by using RECORD_FIELDNAME
document.getElementById("GRS_TEST_WRK_DESCR1").value = OSName;
(There's a lot of useful information online to help understand how to reference HTML elements.  Here's a good place to start https://www.w3schools.com/js/js_htmldom_elements.asp ).

(3) Pass the hidden field into the Component Buffer.  Because our JavaScript has been used to set a field  the data is still on the local browser and will not be available to PeopleCode in any events until the next roundtrip.  This can be a Save, Refresh, non-deferred FieldEdit/Change, RowInsert/Delete, etc).  Think of it as if a human had just entered the data into a field.   

In Summary

If we put all this together this is what's happening.
1) We add our JavaScript is added to the page in Page Activate. (The JS hasn't run yet).
2) The Page HTML is generated by the Application Server and returned through WebLogic to the browser.
3) The browser renders the HTML and, if we've been clever (or lucky), our JavaScript will execute once the page is loaded.
4) The JavaScript grabs the data we're interested in and sets the value property of our Invisible, Modifiable by JavaScript, Generate in HTML enabled Page Field.
5) This Page Field is part of our Form and so will be passed back to be included in our Component Buffer during the next roundtrip (Save, Refresh, non-deferred FieldChange/FieldEdit, etc).
6) Once it's in the Buffer we can get to it like any other Field.

I hope this is useful to someone.  There might be other ways of doing this and other observations, gotchas or things to look out for so please feel free to share in the comments below.


No comments: