One very handy, yet very mysterious property in the PeopleTools page fields is the so-called Modifiable by JavaScript property. This property is available under the Use tab of user-input page fields. It is used to be labeled Modifiable from HTML on the earlier versions of PeopleTools (8.2x and earlier). This property is mysterious because its use is not documented thoroughly in PeopleBooks. Only a passing remark on the property is made to describe it under the Application Designer PeopleBook:
Modifiable by JavaScript – This is a security-related feature and should always be cleared unless you are familiar with modifying an invisible field using JavaScript in an HTML area. If the Invisible check box is cleared, Modifiable by JavaScript is cleared and unavailable for entry. If the Invisible check box is selected, this check box is cleared, by default.
Personally, I think most people won’t find that description useful at all – it appears to be worded in such a way to discourage its use. The new name, too, is unfortunate: it appears to be aimed at further scaring the developer from its use by declaring it has something to do with, or requires, JavaScript (see side note below). The previous terminology of Modifiable from HTML is more technically accurate. The description is also very open to misinterpretation, at first glance it would seem that the field will be rendered as a hidden form element in the underlying HTML. However, this is not the case.
So what is it for? Basically, when you have a field with Modifiable by JavaScript property turned on, you could associate (bind) that field to an HTML form element inside an HTML Area. This is done by setting the name attribute of an element to the Page Field Name (if provided) or to RECNAME_FIELDNAME of the field (if Page Field Name is empty)[1].
When a server trip is performed, the buffer of the page field will be updated with the value of the form element you’ve created within the HTML Area. In essence, Modifiable by JavaScript allows the developer to take control of rendering the HTML element of a page field.
An Exploratory Example
This can be illustrated by the following example.
Consider the following SQL Table record (DEMO_TBL):
![]()
and the following page (DEMO_PG):
![]()
![]()
Note the following in DEMO_PG:
DEMO_TBL.TEXT1is invisible and the Modifiable by JavaScript property is checked. The Page Field Name is set toMOD_BY_JS
The HTMLArea contains the following constant:
<input title='Enter a text value' type='text' name='MOD_BY_JS' value=''/>
And then, the following PeopleCode was added to DEMO_TBL.TEXT1.FieldChange:
DEMO_TBL.LONGVALUE = "DEMO_TBL.TEXT1 has the following value: " | DEMO_TBL.TEXT1;
Now, see the page in action.
Explanation
When the Save button is clicked, a trip to the server is performed. During each trip, all form elements on the page is sent to the server. Because we’ve set the name attribute of the input element on the HTML Area to be the same as the Page Field Name of the DEMO_TBL.TEXT1 field on the page, the value of the input element is associated with DEMO_TBL.TEXT1.
On the first Save action, the component receives the value of “Hello” and detects the change. Therefore, it updates the value of DEMO_TBL.TEXT1 in the component buffer and executes the FieldChange. When the page was refreshed, we can see that the LONGVALUE field was indeed updated by the PeopleCode.
What’s the problem? When the page was refreshed after the first save, the input element became empty again. This is because the value of the input element stored in the HTML Area page field didn’t change. When PeopleTools rewrites the HTML page, it simply takes the contents of the HTML Area and re-insert it on the specific point in the page. It would be the developer’s responsibility to update the content of the HTML Area. Remember: the developer is in control of rendering the element.
When the page is saved the second time, the value of the input element sent to the server is blank. This is different from the value in the component buffer, which currently have the value of “Hello”. Again, the component processor detected this change, updated the component buffer, and triggered the FieldChange PeopleCode.
Modification. Let’s go back to the page and modify the HTML Area to point it to the derived field DERIVED_WORK.HTMLAREA.
![]()
The following PeopleCode was added to DEMO_TBL.TEXT1.RowInit:
DERIVED_WORK.HTMLAREA = "<input title='Enter a text value' type='text' name='MOD_BY_JS' value='" | DEMO_TBL.TEXT1 | "'/>";
The input element must also be updated when the field value is changed. So, the same code was also added to DEMO_TBL.TEXT1.FieldChange, giving:
DEMO_TBL.LONGVALUE = "DEMO_TBL.TEXT1 has the following value: " | DEMO_TBL.TEXT1;
DERIVED_WORK.HTMLAREA = "<input title='Enter a text value' type='text' name='MOD_BY_JS' value='" | DEMO_TBL.TEXT1 | "'/>";
Let’s see the page in action.
Explanation
The value in the input element is updated to reflect the values of DEMO_TBL.TEXT1. This is done when the component buffer is initialized and when the buffer data is changed. The result is the expected behavior of an edit box.
What’s the problem? When the value '><hr title='hi was saved into DEMO_TBL.TEXT1, the resulting content of the HTML Area became
<input title='Enter a text value' type='text' name='MOD_BY_JS' value=''><hr title='hi'/>
By closing the input tag, the user was able to introduce another HTML element—a horizontal rule—into the page.
The issue is somewhat similar to SQL Injection. However, the reader may initially think this is benign because it just involves HTML rendered on a page, and the result would just be a broken page layout. Actually, if the length of TEXT1 is long enough, it will be open to a Type-2 XSS exploit. So, it is imperative that this issue should be always considered and addressed.
Modification. To address this issue, the data must be properly escaped in the HTML. The PeopleCode function EscapeHTML() is designed to do this. The PeopleCode that updates the HTML Area is modified as follows:
DERIVED_WORK.HTMLAREA = "<input title='Enter a text value' type='text' name='MOD_BY_JS' value='" | EscapeHTML(DEMO_TBL.TEXT1) | "'/>";
Again, let’s see the page in action.
Explanation
The length of the TEXT1 field is only 15 characters. Even though the value sent to the server is more than 15 characters, the component enforces the 15 character limit and ignores the excess characters. This is a good security feature. The only issue is that our application isn’t user-friendly by allowing the user to enter more characters than the server would accept.
Modification. Finally, one last tweak to address this is to add a maxlength attribute to the input element. The PeopleCode that populates the HTML Area is changed to:
DERIVED_WORK.HTMLAREA = "<input title='Enter a text value' type='text' name='MOD_BY_JS' maxlength='15' value='" | EscapeHTML(DEMO_TBL.TEXT1) | "'/>";
Conclusion
Although the above example doesn’t really present a very compelling scenario, I hope it clearly illustrates the functionality of the Modifiable by JavaScript property. Using this property, we were able to take control of how our input element is rendered on the page. In this case, we were able to add a title attribute which allows us to assign a hover text to the edit box.
This property does open up a lot of practical possibilities: representing a field as radio buttons in which the number of options is dynamic; creating controls that are not available in PeopleSoft page designer (e.g., dropdown lists with option groups); usage as a hidden element for connecting javascript events on the page to PeopleCode… I’ll try to discuss more of these techniques in future posts.
The example also highlighted the following points. Keep these in mind when using the Modifiable by JavaScript property.
- When using this for displaying your custom control, make sure that the HTML Area is always updated with the current value. RowInit and FieldChange are normally the only location where you need to do this.
- Always escape the data written back to the page
Other facts about Modifiable by JavaScript not explored in the above example:
- When the modifiable-by-javascript record field is set by PeopleCode to disabled or display-only, the server would ignore any changes coming from the client
- When the entire page is set to display-only by PeopleCode, the server would also ignore any changes coming from the client
Side note
It’s not saying that you should disregard the said security warning in PeopleBooks. You should turn this property off if you’re not using it. PeopleTools has built-in security which guards your applications from reading tampered data from the client web browser. For example, when you’ve disabled a field via PeopleCode, the Application Server will ignore this field even if the user tampered with the page’s form fields. (One way to tamper web page form fields is by running javascript through the address bar or bookmarklets.) For an example of tampering, open up a PeopleSoft portal page which has disabled input boxes. Now, enter the following at the address bar of your browser:
javascript:(function(){var x=top.frames[2].document.forms[0].elements;var y;for(var z=0;y=x[z];z++)y.removeAttribute('disabled')})()
Notice how all the disabled input fields are suddenly editable. Now, try editing those fields and perform a server-side action like saving. PeopleSoft will simply ignore whatever values are in the disabled fields. In essence, the Application Server keeps track of what fields are editable and does not accept all data posted by the client.
If Modifiable by JavaScript is turned on for an invisible field, a user can attempt to set that field’s value by inserting a form element dynamically through DOM methods in JavaScript.
[1] This is true only for level 0. For lower levels, a suffix of $n is needed where n depends on the occurs instance of the field on the page.
This is a wonderful piece of analysis and code. Very much appreciated for the work with neat examples and demos.
Hi,
In my scenario I cannot use a SQL record for the mentioned solution. I can use only a derived work record. I tried the steps as mentioned above but was not successful.
Please advise !
Surya,
This functionality is not limited to a SQL table. It would work the same way on a derived field, except that the data is not saved to the database.
My Requirement is something like this.
I have a page with Two Levels that is LEVEL 0 and LEVEL 1.
*********on LEVEL 0 I have ************
SUBPAGE DERIVED_WORK_BI,
SUBPAGE BI_PB_WRK,
SUBPAGE BI_HDR,
SECPAGE
*************Level 1 SCROLL AREA I have *********************
3 fields from BI_HDR_NOTE record ,
1 Field From NOTE_TYPE record,
1 field (Long Edit Box) from DERIVED_WORK_BI record,
1 Field from STD_NOTE_EF_VW
Limit of the LONG EDIT BOX field is 254 characters. On Page LONG EDIT BOX allows you to enter more than 254 Characters but when you save the page it will automatically truncate the data after 254 chars. Here I was planning to Place HTML area and display how many Characters are left while USER entering the data in the long edit box. I wanted to place the HTML AREA as field from DERIVED_WORK_BI
Example : If User entered 54 chars then in the HTML Area I have to show how many chars remaining to be entered.
Here I have to Link Up Long Edit Box with HTML Area. While I am keying in the data in Long Edit Box I have to Count the chars and display in HTML Area.
Can you please guide me thru this. How to Approach and What is code that I need to use and where?
I really Appreciate if you can Provide me the guidance.
Sree,
You can use this as a starting point: http://peoplesofttipster.com/2007/07/24/counting-characters-in-a-field/
Thanks – this helped me in my quest to do some client-side page updates, validation and confirmation.
Thanks for your help.
I have learned the concept from here and implemented this technique on a grid and is working fine for multiple rows being entered. In this I was populating a drop down list in HTML Area dynamically and selected values were being saved in corresponding PS field on save.
I am going to write a blog on this on toolbox.com which will give more insight into the concept.
Its all was possible because you have explained the concept so well here.
This is great! I was always wondering where I could use this and I finally found a use!! Thanks for the insight! This helped a lot!!
Cheers!!!
This article is of great help.
This helped me in creating new controls on the peoplesoft page which are otherwise never possible.
Thanks a lot for this great article!!!!
This is a real gem indeed. I cam across this about 2 years back, but just now made use of this … but critical use. Using this, I was able to do that which I couldn’t do otherwise, and that was to trigger PC off of HTML areas controlled by JS. I tied the HTML generated input field to a derived field and triggered the FieldChange PC of that field at will by assigning a random number to the input field. Now, my JS can generate page content and interact with the DB via iScripts, and also trigger component PC to utilize the same app package to take that content and wrap it up for storage in the DB as well as maintain the online content AFTER a server interaction. Many Thanks!
I have used this concept successfully in a L1 grid. However, I do not want deferred processing on the fields I defined in the HTML area within my grid so I added
onchange="oChange_win0=this;"
to my HTML field to trigger the fieldchange event of the hidden field immediately. This works with the exception that it breaks the normal field focus processing. For example, if I leave the HTML field using the tab key the focus does not go to the next field. Any suggestions for getting the normal focus processing to work (e.g. tab key, mouse click to another field)?
Tom S,
I haven’t tried this yet, but have you tried assigning tab index value to your generated controls then loop through PTools-generated controls’ and alter their tab index?
Great tip on the onchange processing. To make it more flexible though, use “oChange_%FormName=this;”
ChiliJoe,
I did try changing the tab index and it did not solve fix the field focus issue. But I did trace the root of the issue to the delivered javascript function setFocus_win0. The complete solution is complicated and involves replacing the setFocus_win0 with my own revised version of the function.
And thanks for the tip on using %FormName!
Thanks, I used this to browse the local directory and get the file name for processing, instead of using the cumbersome AddAttachment functionality.