JavaScript is a critical component of PeopleSoft applications. With the web browser pretty much taking over as the rendering engine for enterprise applications, I see JavaScript as a critical language for computer professionals. Of course, technologies like PeopleTools and ADF contain abstraction layers so application developers do not have to write JavaScript, but, in the end, someone has to write the JavaScript generated by those abstraction layers. And, if something goes wrong, odds are very good you will have to dig through the generated JavaScript to see what went wrong (where, when, why, etc).
Anyway, I think JavaScript is one of the most important modern languages a programmer can learn, and I know I'm not alone in this opinion. Of late, I've found some very interesting online resources for people interested in learning JavaScript, so I wrote this post to pass those resources along to PeopleSoft developers.
I will maintain this as a "Meta-blog" post and update it as I find more resources. I will attempt to keep the list short, so you don't have to sift through thousands of irrelevant tutorials. Restated: this is not a complete list. It is just a short list of tutorials that I think stand above the rest.
- Eloquent JavaScript Beginner This is a very well done, hands on JavaScript tutorial. It is released under the Creative Commons license so you can download it and run the tutorials from your laptop while traveling, etc.
- JavaScript Garden The Quirky parts of JavaScript
- The JavaScript Module Pattern Advanced
- OOP in JS, Part 1 : Public/Private Variables and Methods
- OOP in JS, Part 2 : Inheritance
- jQuery UI Dialogs in PeopleSoft
52 comments:
Hi Jim
I'd be honored if you would include links to my JavaScript-related posts.
http://danielkibler.blogspot.com/2010/10/using-jquery-in-peoplesoft-introduction.html
http://danielkibler.blogspot.com/2010/11/using-jquery-in-peoplesoft-validating.html
http://danielkibler.blogspot.com/2010/11/using-javascript-in-peoplesoft-proxy.html
I have a new one drafted I hope to post soon.
Regards
Dan
I just added a new JavaScript-related post to my blog.
Using JavaScript in PeopleSoft: Creating your own dialog boxes
Dan
Hi Jim,
I have been an ardent follower of your Journal/book. You have been my inspiration as far JS in PeopleSoft goes.
So i have been experimenting with JavaScript, jQuery & PeopleSoft. I thought of spicing up my PeopleSoft system by replacing static navigation options with some CSS based navigations.
But for the actual work to be done, I still used the PeopleCode. For instance, I defined my custom hyperlink as say: " %SubmitScriptName(document.%FormName,'UN_HRS_APPL_WRK_ADD_PB');".
So I can spice it up as if it was a custom link and still get the PeopleCode to fire.
But i've into problems. As soon as the PeopleCode fires, it clears all my injected JavaScript.
Say i have my script in a HTMLAREA. Before the code fires through my'%SubmitScript' the script is available in my Pagesource, but it disappears as soon as the code fires.
Do you happen to know why this would happen?
Hi Jim,
I've run into an interesting situation while implementing the custom UI scripts ideas in your book. It appears that the javascript gets loaded twice on delivered pages but only once on custom pages. I discovered this by trying to find a way to reliably get the page name across all (or the majority of) pages. As an example: if I add a new script (say, alert("test")) and attach it to any delivered menu/component i will get two alerts. If I attach it to a custom menu/component I only get one alert.
I noticed the help link in the pagebar uses the page name as the context id parameter. I was attempting to strip the page name from this URL. I still haven't tracked down why, yet, but the URL is populated on the first loading of the javascript but blank on the second loading of the javascript (which prevents me from using the help link to get the page name).
Have you seen this before? If so, do you know why it happens? (Also, I'd be happy to explain what we're using your fantastic utility for if you're interested.)
thanks for your time!
Paul
@Manoj, I think I would have to see it to know what to do about it. I don't think I've attempted to do what you are trying to do.
@Paul, that is very interesting. Whether the component is custom or delivered, it should behave the same. Do your custom components use the same CREF template? That is the only thing I can think of -- if your code is firing for both the header frame and for the TargetContent frame.
To find the menu, component, or page name, I use the strCurrUrl JavaScript variable.
Jim, Have you had a chance to test your javascript from the book on peopletools greater then 8.51.05? We're on 8.51.07 and it looks like oracle has locked down some of what you're allowed to do. Document.write is no longer allowed, for instance and appending scripts to the head is also working differently. They've even stopped you from inserting closing script tags in html definitions.
@Paul, yes I have had a chance to implement some of the code on PeopleTools 8.50, and now 8.51. The key difference is $(document).ready. It doesn't work the same because PeopleTools no longer reloads the page. Instead, I use a technique called "Monkey patching" or "Duck punching." What I do is override the net.contentLoader (or something like that, can't remember) in a closure so I can do additional processing. I think my book's JavaScript for changing the search operator has some of this code in it.
@jim: we have a requirement where in we dont want the 'Add an Attachment's pop up on the main page. The pop up contains Textbox, browse, upload and cancel button. when user clicks the 'Add an Attachment' button, user shuld be shown the File browse dialog, if a file is selected then the file should be uploaded. Our customisation for tools less than 8.50 did not work in 8.50, as we have pop up. Is there a way to do this. atleast with jQuery.?
@citizen6in, I have not tried that before. I see your point though. Why show that prompt? Why not just open the file dialog? Since I haven't looked into the JavaScript for the Add Attachment button, I can't give you much more than just a place to start. Add Attachment buttons usually execute FieldChange PeopleCode. In 8.50 this will cause an Ajax request/response. I suggest you use Fiddler/Firebug to inspect the Ajax request and response. In there you should see the JavaScript required to display that dialog. Once you discover the JavaScript behind the buttons, you can start Monkey Patching the methods/functions so that they behave the way you require.
I have used jQuery to manipulate grids so that the "Click column heading to sort ascending" title is changed to "Click column heading to sort ascending by fieldname". This was to help with some 508 Compliance issues with PeopleSoft.
/* Set the hover text for the column headings */
$('a.PSLEVEL1GRIDCOLUMNHDR').each(function (index) {
var hdgObj = $(this);
var hdgTitle = hdgObj.attr('title');
var hdgText = hdgObj.text();
if (hdgTitle.indexOf("by") !== -1) {
}
else
{
var newTitle = hdgTitle + " by " + hdgText;
hdgObj.attr('title', newTitle);
}
})
Anwway, I need to do the same for the search pages and I have yet to figure out where the code is for building the search results so that I can manipulate things. I have noticed that my code does not get fired when the search button is pressed, so I am assuming that I cannot use the $(document).ready(function (), since PeopleSoft is no longer reloading the page. Any suggestions that you can provide?
Regards,
Marc
@Marc, First, use Firebug to see what scripts are loaded into the search page (PT_PAGESCRIPT, etc). These are HTML Definitions in App Designer. You can use one of them as your delivery vehicle. Second, $(document).ready doesn't fire on PT 8.50 and greater after search button click because the request/response is all Ajax (you already figured this out). In my book (chapter 7) I have an example of Monkeypatching the search page's net.ContentLoader, which is the Ajax service for PT 8.50. My example shows how execute a function after the advanced search button click returns a response. Your scenario would be very similar.
If you use something like PT_PAGESCRIPT as your delivery mechanism, then you need to have a way to determine if you are on a search page. Here is what I use:
if($("#\\#ICSearch").length > 0) {
// search page
} else {
// do nothing
}
Hi, recently we have upgraded our PeopleTools from 8.49.23 to 8.52.09.
After this we are facing the issue like the processing image is keep on running. For ex: If I navigate to Structure and Content --> Portal Objects --> Home Page-->Tabs -->Home
In that if I am clicking any tab it will load the page but the processing image keeps running. I see an error in the status bar like below
Webpage error details
User Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Timestamp: Thu, 11 Oct 2012 05:19:41 UTC
Message: Permission denied
Line: 1602
Char: 5
Code: 0
URI: http://askhrtest.hk.standardchartered.com:8522/cs/DGEPUPG1/cache/PT_PAGESCRIPT_win0_291.js
Message: Permission denied
Line: 1602
Char: 5
Code: 0
URI: http://askhrtest.hk.standardchartered.com:8522/cs/DGEPUPG1/cache/PT_PAGESCRIPT_win0_291.js.
Sometimes it is showing permission denied error on PT_COMMON script.
We are not facing this issue when we do the same thing in Chrome Version 22.0.1229.79. But our organization standard browser is Internet Explorer .8.0.6001.18702
Please help us to find the issue.
Thanks for your time.
@krunal, did you set the Auth Token Domain in your web profile?
You might get better results if you post this question in the PeopleSoft OTN Forum.
Auth token is set up at the web server level and also at the web profile. Not sure how do we need to analyze/fix this issue. Please guide us to resolve the same
@Krunal, the brightest PeopleSoft minds in the world monitor the OTN and ITToolbox forums. Here you will only get my assistance. Post your question in either the PeopleSoft OTN general forum or the ITToolbox PeopleTools forums and I'm sure someone that has experienced that issue will respond.
Dear Jim,
We have finally found the below error is not due to the permission issue
Message: Permission denied
Line: 1602
Char: 5
Code: 0
URI: http://askhrtest.hk.standardchartered.com:8522/cs/DGEPUPG1/cache/PT_PAGESCRIPT_win0_291.js
It looks like there is some problem with the Java Script execution. While loading the page JS getting error and stops further processing due to this we are getting the processing image as its waiting for the execution to complete.
When I try to debug the JS error it stops at the below line (which is given as bold text)
function doModalOnLoad_win0(bStartUp) {
mTop = MTop(); // top window
if (!mTop || typeof mTop.oParentWin == 'undefined' || !mTop.oParentWin) return;
Not sure how this Mtop() is working and what it is expecting to complete the execution? Could you please help us?
Thanks a lot for your time.
@Hari, When your web browser throws a permission denied error, it means the JavaScript attempted to perform an operation that is considered insecure. Usually this is caused by trying to access a frame from a different domain. Make sure the top level page and your transaction page have the same "document.domain" value. You can check this from the JavaScript console in any browser. Also take each fragment of the if statement and execute it in the JavaScript console to see which part is throwing the access violation. Don't be surprised if the error is really somewhere else in the JavaScript.
Another thing you can test is adding your PeopleSoft application domain to your list of trusted sites.
Jim,
Love your Blog! I'm trying to bind a JQUERY click event to a PeopleTools Button/HyperLink field (TYPE: Hyperlink, Destination: PeopleCode Command), so that when the user clicks the hyperlink a loader/spinner icon appears and makes an ajax call to an iscript,
but whenever I click the hyperlink it hits PT_PAGESCRIPT:submitAction and it strips the field element of all the attributes I set using my jquery callback function and returns it to the state it was in before I clicked it. I can get this to work using an html area or any other field for that matter, but just wondered if there was a work around for the PeopleTool button.
@Peter, thank you for the compliments.
When creating buttons that look like PeopleSoft buttons, but behave differently, I usually use an HTML Area and copy the HTML from a PeopleSoft button into the HTML Area. I change the ID, name, and onclick handler.
If you want to change the way a delivered button behaves, you will need to reset the onclick attribute $element.prop("onclick", null). For hyperlinks, you can have your $.click event handler return false.
Hi Jim,
I have posted a query related to the browser permission denied error related to the Mtop function in oracle forums:
https://forums.oracle.com/forums/message.jspa?messageID=10905546#10905546
Could you take a look and offer some guidance?
%SUBMITSCRIPTNAME resets all my other javascript code.How do I prevent this.
@Sri, can you elaborate? How are you using this MetaHTML? Where are you using it?
Hi,
I have grid column that needs to be sorted.This column is a HTML area and cannot use the delivered peoplesoft sorting ie(%submitscriptname(form,sortcolumn)).Hence I have written my own javascript code
-> to make the coulmn heading a link
->to sort the column ascending/descending when the link is clicked.
It works fine but once I try to sort any other peoplesoft column or click download or find or in other words when %submitscriptname is called anywhere else all my JS code is reset.My column heading is no more a link and everything is back to initial stage.Is there any way to bypass the reset?
Thanks,
Sri
@Sri, that makes sense. When you click any link or perform any action, it submits an Ajax request. The Ajax response will overwrite the current page contents. Any JavaScript on your page will still exist, but the element bindings will not exist because the former elements will have been replaced by the Ajax response. I am not sure I like this, but it is how it works. One way I work around this is to use jQuery's live method for event binding. Another approach is to "monkey patch" net.ContentLoader so you can rebind your event handler after the Ajax response.
Hey Jim,
We have had multiple issues with ePerformance and our users wanted to autosave the document if the manager click's on the back button. So I was looking into doing a simple like this:
window.onbeforeunload = function () {
// stuff do do before the window is unloaded here.
submitAction_%Formname(document.%Formname,"EP_BTN_LINK_WRK_EP_STORE_PB");
// alert('Auto Save');
}
But the save only works if the alert is fired after the submitAction function? Is there a way to autosave the page if the window is unloading from either the back button or even regular navigation within the component without the alert? And if you could tell me why this only works with the alert, that would be super as well!
Thanks!
@Kevin, I am suspecting it has something to do with timing and the request/response. With an alert, the full request/response can happen for the save. Without it, the browser is just changing pages and killing the save request. You can probably see this in Firebug. The save request would be highlighted in red in the console, and then disappear as the new page loads.
I really only want the onbeforeunload to happen if the user clicks the back button. So I attempted to change the onclick event of the hyperlinks like this...
function adaptLinks() {
var links = document.getElementsByTagName('a');
for (i = 0; i != links.length; i++) {
links[i].onclick = (function () {
var origOnClick = links[i].onclick;
return function (e) {
window.onbeforeunload = function(){ };
if (origOnClick != null && !origOnClick()) {
return false;
}
}
})();
}
}
adaptLinks();
This prevents the onbeforeunload and fires the onclick method associated with the link. I wonder if I could use jQuery or something cool like that to select all the input buttons and hyperlinks to override the onclick to blank out the onbeforeunload and call the default onclick event. Then change the onbeforeunload to ask the user if they want to navigate away from the page without saving.
Thanks for you input!
Kevin
@Kevin, I like your approach of capturing the link click before it happens. Yes, you could use jQuery to identify and handle click events. Another alternative is to monkeypatch a method like saveWarning so it calls your save if the user chooses cancel. You will also want to monkeypatch the timeout so that it saves before timing out.
Hi Jim,
I am on HRMS 9.1 and Tools 8.51. On the compensation page we have 3 grids at level 1 with almost 100 columns in total.
1) There are 2 issues one if the number of rows in the grid reaches more than 80 the page fails to load.
2) Out of the 100 fields in all the grids at most 5 to 6 fields are editable. If I load around 75 rows in each grid the page loads but on a grid field change there is minimal time taken up by appserver in contrast webserver rendering the page is having a processing time of 6 to 8 sec each for a field.
The business user wants more than 100 rows to be displayed on the grid and also have the field change work within 3-4 sec.
I am not sure how to approach the issue to show more than 100 rows in the grid without crashing the appserver, I am more interested in getting the field change work lot quicker.
We have tried many options in the setting and cache and nothing helped. I have seen your post on Jquery, can I make the component differed and use a Jquery to mimic the calculation in the field change on the grid to avoid the appserver and webserver overhead?
Please suggest,
Regards Ricky.
@Ramee/Ricky, yes you can use Ajax (jQuery) to perform the calculation if the data exists in the database. What you would do is add an HTML Area to the grid with a button and some JavaScript to execute on click. This replaces your FieldChange. The JavaScript will make an Ajax request to an iScript to perform the calculation.
If all of the data already exists on the page, the you can perform the calculation with JavaScript and skip ajax.
Hi Jim,
I have successfully added an HTML Area to a page that uses jsTree to display a list of checkboes with multiple levels for a user to select.
Once a user selects checkboxes from the jsTree, I am able to execute an iScript via a javascript button that sets the querystring with the users selected. Once the iScript has been executed, I get the list from the querystring and process accordingly.
However, I am unable to add a PeopleSoft button to the page that calls a javascript to pull which checkboxes are selected. When the button is clicked, the jsTree is re-loaded and I lose the checkboxes that the user selected (even with using jsTree state property, I can't pull the selected checkboxes). I haven't been able to figure out how to stop the automatic refresh of the jsTree from loading when a PS button is clicked. This is the preferred method over iScript as I don't want the page to reload, nor do I want to add to the querystring.
Any help is greatly appreciated.
As always, thanks for your help and your blog is a fantastic help and resource!
@Robert, I think what you are experiencing is PeopleSoft replacing the page's contents on FieldChange. I believe the "hack" would be to Monkeypatch net.ContentLoader to restore the state of the jTree. You can see examples of Monkeypatching net.ContentLoader in my posts Mnkeypatching PeopleSoft and Changing the Search Page Operator
Hi Jim,
Love your work!
I have a page and on it I put some html, javascript and use a JQuery library. It all works, but when I click a button on the page which uses standard FieldChange, it repaints the whole page so all my HTML and javascript disappears. Do I need to do something special so that PeopleCode and HTML/Javascript can co exist ?
Thanks.
@Jase, that is true, and is an unfortunate side effect of the way PeopleTools implemented "partial" page refresh (I put partial in quotes because I wonder how they define partial). Since the page does not reload, just the content through Ajax, any JavaScript objects attached to the window object will exist after a FieldChange event. For example, window.jQuery will exist both before and after.
If you have an HTML Area that has jQuery, then jQuery will reload after every FieldChange. The trick I use is to wrap the jQuery library in this JavaScript: if(!window.jQuery) { jQuery lib content here }. I actually modify the jQuery JavaScript library file. I do the same with any jQuery plugins, but test for the existence of the plugin. I actually wrap ALL of my JavaScripts in this manner. It is sort of like C-style include protection, but for JavaScript.
Another alternative is to place all of your code in a common HTML definition such as PT_PAGESCRIPT and then evaluate the URL to determine if PT_PAGESCRIPT is executing on your component. My PeopleTools Tips book has a chapter on creating a configurable version of this.
The best alternative comes with PeopleTools 8.54. It is an online configuration page that allows you to inject any JavaScript into a component. You can do this globally or specify a component.
ok, great. Thanks.
Hey Jim,
I tried to implement your recommendation for @Jase and am running into issues.
Before the fix you recommended, I had the following:
I pass in the libraries.
I then commented out that code and replaced with the following:
if(!window.jQuery)
{
var s = document.createElement("script");
s.src = "%bind(:1)";
document.head.appendChild(s);
var t = document.createElement("script");
t.src = "%bind(:2)";
document.head.appendChild(t);
} else {
}
When I test, the initial load does not display the tree. When I click a JS button that initiates a fieldchange event, then the tree does display. Each time the JS button is clicked, the tree is refreshed.
I thought the code above would initially load the tree and then when fieldchange is executed, it would not refresh.
Any help is greatly appreciated.
Thanks.
@Robert, I can't confirm, but I'm suspecting that what you are experiencing is the asynchronous nature of scripts loaded AFTER the the DOM is ready. script tags are loaded synchronously while a document is loading, but asynchronously if appended as DOM elements in the manner you demonstrated. My recommendation was NOT to add "if" tests to the place where you want to include the library but rather to open up the library and modify it. Put that wrapper right in the library itself. Then you can put all the script tags you want into your code, but the script will only parse once. That is the way C header files work as well (ifdef, etc). You put the criteria in the header, not the place where you use the code.
If you prefer to put the test in the location where you import the library, then I recommend using a script loader like $script. I like this one because it is light weight. If you minify it, you can embed it in one line. Another alternative is to create your own loader using either Ajax or a script tag event handler. The key is to make sure that your dependencies resolve in the correct order.
Hello Jim,
Wonderful insight into how to javascript in peoplesoft. I have a requirement for which I have been struggling for a while.
We have a grid; and one of the columns is check box. If user clicks check box on a row; I need to show a confirmation popup. If user hits Yes on the confirmations I need to continue with the actual fieldchange of the checkbox; and else if he hits cancel I need to undo the check/uncheck done by him.
Some how controlling checkboxes had been tricky. Kindly help.
@Sans, checkboxes have a checked property. Once you have a reference to a checkbox, you can test its value by accessing the checked property. You can also uncheck it by setting checked = false. A great way to get a reference to a checkbox is to include jQuery or use querySelectorAll as in document.querySelectorAll("input[type='checkbox']").
Previous conversation:
@Ramee/Ricky, yes you can use Ajax (jQuery) to perform the calculation if the data exists in the database. What you would do is add an HTML Area to the grid with a button and some JavaScript to execute on click. This replaces your FieldChange. The JavaScript will make an Ajax request to an iScript to perform the calculation.
If all of the data already exists on the page, the you can perform the calculation with JavaScript and skip ajax.
Hi Jim,
Thanks for inputs. Just few more questions:
1) can we access the data from the component buffer/rowset through JavaScript? The reason is the calculations once field changes is based on values in the rowset and may not be not all be on the page.
2) Business say its difficult to click the button every time they change a field and there are 8 such field changes. Can we call the java script on change event?
3) Jquery when it fetches from database and we calculate the values and repopulate on the grid we would need to save the component so the next field change calculation gets the correct values am I correct here? If so can we trigger a save component via the java script?
Thank you so much for your time and inputs.
Regards,
Ramee
@Ramee, technically, no, Ajax has no access to the component buffer. It is possible to accomplish what you want, however, but is a hack you will have to verify each release. The way I would approach this is to inspect the PeopleTools Ajax request/response cycle when you click the button and then write JavaScript to replicate that request. You might even set a JavaScript/browser breakpoint on the button so you can see the PeopleCode that is called.
Hi Jim,
We are trying to embed online calculator in our PeopleSoft Portal Home page. I have java scripts,html,images style sheets provided. Where should i deploy these files in the web server to display the online calculator on the home page, any idea please?
Thanks,
AK
@AK, it is best not to put anything in your web server because you have to manage it through PeopleTools upgrades and synchronize it across load balanced web servers. Alternatives include placing on a separate, non-PeopleSoft web server or uploading all of the pieces into managed definitions in App Designer (or using the 8.53+ Branding objects component). The HTML can either be in a Pagelet Wizard pagelet or an iScript.
Thanks so much for your response Jim.
Regards,
AK
@AK, hopefully that was enough information to give you direction.
Hi Jim,
I have a requirement in such a way that I need to execute a JavaScript in ALL transaction pages commonly to find out a field (for e.g., salary) using DOM. The target pages are loaded inside an iframe. The fields that I am trying find are lying inside these iframes. Which html (or anywhere else) will be suitable to add this JavaScript?
@Muthu, when you say, "iframe," if you are referring to the standard PeopleTools iframe and the content is the component page, then a JavaScript HTML definition common to all components is PT_COMMON. This is where I place JavaScript in pre-8.54 environments. In 8.54 and higher, I use the branding system options page to insert JavaScript globally into all components. Earlier versions of PeopleTools 8.5 and lower (not sure if it was 8.52 or 8.51) used PT_COPYURL, which was a VERY small HTML definition. That was my favorite because it was small so it was easy to locate customizations.
Hi,
I came across one of your comments on an issue (http://peoplesoft.ittoolbox.com/groups/technical-functional/peopletools-l/performance-on-load-peoplesoft-grid-2675447) and am looking for more guidance on the same. We have a PS page with a grid on it that times out whenever there are a lot of rows that need to be loaded. What are some of the ways I can use to improve performance on it? I've not worked with jQuery but am open to learning about it and trying it as a solution. Any help will be appreciated. Thanks!
@Nandini, I don't know of ways to improve performance. As the comment stated, I just know of a way to lazy load the rows or paginate the rows. This involves adding an HTML Area to the page along with a Derived/Work record field and an HTML definition. There are many lazy load table alternatives and I have no recommendations on which to use.
The iscript data source for the paginated or lazy loaded table will require parameters to identify which set of rows to display.
Part II of my PeopleTools Tips and Techniques book provides a lot of guidance on using jQuery with PeopleSoft. It does NOT show a lazy loaded table, but should give you the foundation you need to implement one.
Hi Jim,
I'd like to run a solution I've come up with regarding the 'getting the page name in javascript' question by you. If you post to the current url with (at least) two passed parameters - ICAJAX=1&ICAction=%23KEYCJ - you'll receive a response with the information from the CONTROL+J information page. One of the first elements is the PAGE tag, which has the pagename as the id. It's pretty simple to grab that value and use it for whatever script is executing. Is there any reason not to go about getting the page name this way? So far it's the only way I've found to reliably get the page name regardless of location in the application.
thanks,
Paul
@Paul, great information. No reason not to use it.
Post a Comment