Thursday, July 2, 2015

Invoke PeopleCode Event from Javascript (in a HTMLAREA)

Let us walk through an example on how to invoke a peoplecode event from a javascript in a HTMLAREA.

Here is a test page which contains a push button that display a winmessage on FieldChange.


Let us see what happens behind the scenes when we click on the push button by inspecting the HTML.


We can see that the onclick event on the push button invokes the javascript function (delivered) submitAction_win0(document.win0, this.id, event). In this case, this.id would be equal to CSK_TEST_WRK_TEST. The general format for the id field would be <RECORD_NAME>_<FIELD_NAME>. This would translate to <RECORD_NAME> = CSK_TEST_WRK and <FIELD_NAME> = TEST.

Now let us include a HTMLAREA on the page.


Include the following HTML and javascript in the HTMLAREA properties. Note: I am using a constant HTML value for the purposes of this example.


HTML Code:

<script>
function myFunction() {
   submitAction_win0(document.win0,"CSK_TEST_WRK_TEST", event);
}
</script>

<a href="#" onclick="myFunction()">Push Button in HTMLAREA</a>

Updated HTML Code - 20151105 - Thanks to @Santiago.gmerino's comment below:

<script>
function myFunction() {
   // submitAction_win0(document.win0,"CSK_TEST_WRK_TEST", event);
   // Use %formname to resolve _win# dynamically.
   submitAction_%formname(document.%formname,"CSK_TEST_WRK_TEST",event);
}
</script>

<a href="#" onclick="myFunction()">Push Button in HTMLAREA</a>

Now let us test the javascript in the HTMLAREA.


We can see the hyperlink that we added in the HTMLAREA appear on the page. Let us click the hyperlink 'Push Button in HTMLAREA'. This should trigger the FieldChange event on the push button CSK_TEST_WRK.TEST.


Note: At the time of writing this post, I am using HCM 9.2 PUM Image 12 - PeopleTools 8.54.08.

57 comments:

  1. Sasank, win0 works only on an initial session. If you were navigating in Psoft with a browser session opened with the 'new window' link. your session's objects will have win1 or win2, etc. The url in peoplesoft will also show you the session appended to the db instance as _1, _2, etc. The script is still referencing win0 which does not exists, the actions wont work.

    ReplyDelete
    Replies
    1. @[Sara -kiki- Llewellyn] Thanks for pointing that out! I certainly took a short cut with that function call.

      I will try to write some dynamic javascript to make the code independent of the window counter. I will update this post when I get a chance!

      Thanks again for point that out! :)

      Delete
  2. No need to create a function to replace win0 but only use the variable %Formname ;)

    ReplyDelete
    Replies
    1. @Santiago.gmerino - Thank you! You saved me some time because I never got a chance to get back to this post.

      %formname meta-html is a great way to resolve the _win# subsitution dynamically!

      Delete
    2. Also, updated the post with the latest javascript so that it helps the other bloggers/readers!

      Delete
  3. Thanks Sasank. I was looking for something like this to implement will try this out.
    One question I had. How does App server know that "CSK_TEST_WRK" is the Record and TEST" is the field. Wouldnt it mistake it for "CSK_TEST" to be the record and "WRK_TEST" as field?

    ReplyDelete
    Replies
    1. Hi Jithin - Good question.

      I think id attribute that is generated by PeopleTools (either by default:record+field or the one we assign at the page field level) will be unique (in the context of the component buffer).

      In the context of the actual HTML, the uniqueness of the id is important (concat of record+field name) and it really does not matter what is the record/field portion. I guess the component processor should then be able to simply co-relate the id attribute with the page field.

      Also, if you try to use the same page field name in two different fields on the same page, then you will get this error in App Designer:
      https://snag.gy/hQklEv.jpg

      Hope that makes sense.

      Delete
    2. That definitely makes sense. Thanks for your quick response.

      Delete
  4. Hi Sasank,
    I've somewhat similar requirement.
    I want to call a FieldChange event on click on header of collapsible groupbox.

    How can I achieve it?


    ReplyDelete
    Replies
    1. If this is a Fluid page, then you could use the JavaScriptEvents property on the group box field. Then do whatever you need to do in the JavaScript code.

      Here is a sample of what you can do in Fluid and JavaScript:
      https://pe0ples0ft.blogspot.com/2016/07/fluid-ui-custom-development-invoke.html

      Delete
  5. Hi Sasank,
    Is that possible to send any additional parameters in submitactionform(buttonid,event,?) other than button id and event.

    Rashmi

    ReplyDelete
    Replies
    1. Hi Rashmi - Good question. If I do a 'Find In...' searching all HTML objects for 'submitAction_', I see a few variants of the use of this function, so there may very well be other parameters that you could pass. But I am not sure if there is documentation. Could not find the actual function definition either, so really not sure.

      That said, what are you trying to pass? If you want to pass back data to the PeopleCode event, it is best to pass it as part of the component buffer that way you will be able to access it via PeopleCode.

      In some cases, I have placed a hidden, 'modifiable by javascript' field on the page and use that to pass back data. That is, before calling the submitAction_%formname, I would use some javascript to place my data in the hidden field.

      Hope this gives you some ideas! Let us know what you are trying to achieve and we may be able to provide more options.

      Delete
  6. This works great for me in IE, but it doesn't work in Firefox or Safari. Any suggestions?

    ReplyDelete
    Replies
    1. I realized this problem recently as well (on Firefox). I was able to workaround this by omitting the event parameter as follows:
      submitAction_%formname(document.%formname,"CSK_TEST_WRK_TEST");

      Let us know if that resolves your issue.

      Delete
    2. Hi Sasank, can I know does this function require any specific weblib's Permission or any of such kind. Because, I kept this on an HTML object and it is getting invoked with PS Admin USer/Super User, but not when invoked with limited roles? Any suggestions? Thanks in advance!

      Delete
    3. No. This does not have any additional security other than the page security.

      Delete
  7. Hi Sasank !
    It is a nice post. I tried it and works for me.
    However, if I call DoSave() function in FieldChange event, then I get the following error, although the data is saved successfully.





    Home



    Global Search












    Search



































































    NavBar









    Close









    "This page is no longer available.
    To continue, return to your most recent active page or select one of the navigation icons in the header above."

    Any thoughts on this?

    ReplyDelete
    Replies
    1. I have not seen this error before. I found these documents on My Oracle Support:
      E-WL: Intermittent Issues after Configuring Coherence*Web in PeopleSoft Environment: Users may receive "Page is no longer available" Messages and/or Users are Sometimes Kicked Back to Search Page (Doc ID 1585569.1)

      EGL: General Ledger Online Journal Edit Times Out With Error "Failed To Publish Initial Request Status" (Doc ID 2163214.1)

      The second document seems to suggest there may be some conflict with the Push Notifications?

      Delete
  8. We are trying to implement text counter in PeopleSoft Edit Box we are on V9.1; the below code works perfect in IE but not working in Chrome

    function CharCounter()
    {
    if (document.win0.EP_APPR_SECTION_EP_RESULTS2.value.length > 3000)
    document.win0.EP_APPR_SECTION_EP_RESULTS2.value = document.win0.EP_APPR_SECTION_EP_RESULTS2.value.substring(0, 3000);
    else
    document.win0.EP_BTN_LINK_WRK_COUNTER2.value = 3000 - document.win0.EP_APPR_SECTION_EP_RESULTS2.value.length;
    }
    function AddEvent(obj, evType, fn, useCapture){
    if (obj.AddEventListener){
    obj.AddEventListener(evType, fn, useCapture);
    return true;
    } else if (obj.attachEvent){
    var r = obj.attachEvent("on"+evType, fn);
    return r;
    } else {
    }
    }
    AddEvent(document.win0.EP_APPR_SECTION_EP_RESULTS2, "keydown", CharCounter, false);


    In Chrome the AddEventListener is not working;any suggestion how we can alter the code so that it works for both IE and Chrome

    Mahesh

    ReplyDelete
    Replies
    1. Hi Mahesh,

      Sorry for the late response. I think you have a typo with the AddEventListener method call. It should start with a lower case 'a' as addEventListener. Otherwise, your script seems to work in all browsers.

      I tried this jsfiddle based on your script:
      https://jsfiddle.net/SasankVemana/jt4rehwh/

      Let me know how it goes.
      Thanks,
      Sasank

      Delete
  9. Thanks a lot;)
    I am really thankful to you it helped me it resolved by issue; thanks a lot you made my day.

    Mahesh

    ReplyDelete
  10. hello Sasank,

    Once I am in page, instead of clicking the Push Button in HTML Area, when i come to the page it has to populate the Hello World with out clicking.

    Can you let me know how it can be achievable.

    ReplyDelete
    Replies
    1. Hi Ajay - If you are looking at triggering code in a fieldchange event, why not just replicate the code in the Page Activate event?

      Just trying to understand the requirement better.

      Delete
    2. There is a delivered page, When the User opens the page, instead of clicking the View All button (to view all rows), the User want it to populate all the rows with out clicking the View All button. There is setting in App designer for scroll "Unlimited Occurs Count" but we are getting performance issue (it is working fine for less than 100 rows, if it more than 100 rows it just spins and timesout). So we decided to populate first 100 rows when the user opens the page.For scroll we cannot give 100 rows in the page field properties. So i am trying your code. Inserted HTML object on the page and below is the code. (this is working when i click the Push Button, but i dont want to click it manually, it should click automatically when the User opens the page).


      For some reason i am not able to place the code, the code is same as your 4th screenshot instead of submitAction_win0(document.win0,"CSK_TEST_WRK_TEST", event); i updated to submitAction_win0(document.win0,"$ICField1$hviewall$0").click();

      This is an urgent requirement, if you can send me the updated code, it will be very helpful.

      Thanks in advance.

      Delete
    3. Couple of suggestions:

      - If you want to fire the function right away, try the following line write before the end of the script tag.
      window.onload = myFunction;
      Screenshot
      - Also, replace win0 with %formname (see updated code in the post). Otherwise you will run into issues with this code executing in new windows.

      Hope this helps.

      Delete
    4. Also, avoid the event parameter. I don't think it is required and know to cause issues with FireFox.

      Delete
    5. Hello Sasank,

      script
      function myFunction() {
      submitAction_%formname(document.%formname,"$ICField1$hviewall$0").click();
      }
      window.onload = myFunction;
      /script


      removed <> for script

      I updated the code but the function is not firing right away..

      Delete
    6. Not sure what the problem is in your case. The suggestions that I gave works for me (in the example provided in this blog).
      Video: https://media.giphy.com/media/3og0IP61Om7YrnjgfC/giphy.gif

      You might have to debug your script (write messages to the browser console) and see if you are getting any errors (look in the browser console).

      Delete
    7. Hello Sasank,

      Can you copy and paste your code here please...

      Delete
    8. You can find the script here. It is just one line of code added for you requirement (rest is the same as in this blog):
      https://jsfiddle.net/SasankVemana/j9pa04b1/3/

      Delete
    9. The code is working if you dont have a search record, or if you just have one row in a record. Can you add the search record and let me know if it is working...

      Delete
    10. ajay - JavaScript will only fire one per component load. So if you have multiple rows and you are navigating back and forth to the search page you may have to write additional code to account for those events.

      This is post is just a proof of concept on how to invoke PeopleCode from JavaScript.

      Delete
  11. HI Sasank ..can you send me the code please. I tried but it did not work ...

    ReplyDelete
    Replies
    1. Hi Ajay - I don't have code for that scenario. If I find anything that might help. I will post back on this thread. Thanks!

      Delete
  12. Hi Sasank,
    Thanks for this nice article.
    Can this approach be used for uploading files attached to a form into PeopleSoft using javascript? Is there a way to get the file attachment content and save it to a PS table?

    Thanks

    ReplyDelete
    Replies
    1. I have not tried but it should be possible. You may need to use javascript and potentially javascript events via peoplecode and figure out a way to initiate the attachment upload. Once the request reaches the server side (peoplecode), you would be able to use code that is similar to delivered attachment functionality to load it into a PS table.

      Delete
  13. I have to show the total time entered from different columns from grid into one field so for this i have written a code
    function addTwoNumber(){
    var a = document.getElementById("TIME_TST_TIMEDOUT_LBL$0").value;
    var b = document.getElementById("TIME_TST_TIMEOUTDDTM_LBL$0").value;
    var x = Number(a) + Number(b);
    document.getElementById("COUNTER1").value = + x;
    }
    function AddEvent(obj, evType, fn, useCapture){
    if (obj.addEventListener){
    obj.addEventListener(evType, fn, useCapture);
    return true;
    } else if (obj.attachEvent){
    var r = obj.attachEvent("on"+evType, fn);
    return r;
    } else {
    }
    }
    AddEvent(document.win0.TIME_TST_TIMEOUTDDTM_LBL$0, "keydown", addTwoNumber, false);
    AddEvent(document.win0.TIME_TST_TIMEDOUT_LBL$0, "keydown", addTwoNumber, false);

    Now if a new row is added to grid then TIME_TST_TIMEDOUT_LBL$0 becomes TIME_TST_TIMEDOUT_LBL$1 and TIME_TST_TIMEOUTDDTM_LBL$0 becomes TIME_TST_TIMEOUTDDTM_LBL$1 and if more rows added the $2,$3....etc so now how to code this to take this values dynamically and add them. Could you please help me on this.
    Mahesh

    ReplyDelete
    Replies
    1. Hi Mahesh - Just trying to understand the requirement. Why are you using javascript for this? Can you not use PeopleCode? It may be a lot easier to achieve, unless I am missing something!

      Delete
  14. I tried doing this with peoplecode but the grid is at level 1 and the counter field is at level0 and the calculation is required in realtime; I cannot change the page structure hence was trying this with javascript. Also if i get to learn how to get document.getElementById dynamically i.e. $0,$1,$2 this will be helpful for me in future. Could you please help me on this and Thanks a lot for the prompt reply.
    Mahesh

    ReplyDelete
    Replies
    1. I think where possible we should try to use server side code instead of client side. Even if the grid is in a different level, there are many PeopleCode built in functions and rowset class methods and properties that can help traversing the component buffer. This will be a much better solution and would be in line with best practice. Of course, we can use javascript for cases were server side logic is not possible.

      All that said, here is a link that might give you some ideas.
      https://stackoverflow.com/questions/15874630/get-element-by-part-of-name-or-id

      I have not tried this but in the answer, there is reference to document.querySelectorAll which returns an array. You may then need to iterate through that array to get the elements that you need.

      Delete
  15. Hi,
    Can you tell me, how do i hide the 'save search criteria' from my search page

    ReplyDelete
    Replies
    1. Hi - Someone asked a similar question in another post. Here is my response and solution using CSS:

      https://pe0ples0ft.blogspot.com/2015/01/peopletools-854-component-branding.html#c3782177036040802938

      Delete
  16. Hello Sasank,

    This is a great stuff. I've a similar requirement. We have a tab-separated grid with several tabs. On page load, a specific tab of the grid needs to be clicked on certain condition.

    I added an HTML area with the following code -

    function testFunction() {
    submitAction_%formname(document.%formname,"ZM_PLN_LBRTOTVW_$tab13$0")
    }

    window.onload = testFunction

    But this doesn't work. The page html for one for the tabs looks like this
    /*style="white-space:nowrap;float:right;" class="PSHYPERLINK" onclick="javascript:submitAction_win2(document.win2,'ZM_PLN_LBRTOTVW_$tab13$0');" tabindex="-1" aria-selected="false" onkeydown="return doTabNav(event);" id="ICTAB_1_88" role="tab"
    */
    Please, suggest.

    ReplyDelete
    Replies
    1. @Sufian Shaikh,

      I don't have a way to replicate this and assist you right now.

      I would suggest that you check your browser console for any errors. Also, you could place console.log debug messages in your javascript to see how your code is working and potentially identify your problem. This is a good technique to troubleshoot javascript.

      Hope this helps.

      Delete
  17. Hi Sasank,

    Is there a way to dial Phone number and call the employee from the peoplesoft page ? Could you forward me few link which can help me to implement this requirement.

    ReplyDelete
    Replies
    1. Good question. Here is a link to how it can be achieved.
      https://developers.google.com/web/fundamentals/native-hardware/click-to-call/

      Basically, we need to wrap the content around an anchor tab with a href value.

      Are you trying to achieve this in Classic or Fluid?

      Delete
    2. The page is classic.

      Delete
    3. How can we send the dynamically telephone number of user in this href tag? and how do we need to call it on some image or button?

      a href="tel:+1-303-499-7111">+1 (303) 499-7111

      Delete
    4. It is not very straight forward. The only option I see is to write some javascript to manipulate the elements in the HTML.

      I don't have any examples to share with you.

      Delete
    5. This may not help you since your requirement is in Classic. But here is how we can achieve this in Fluid.

      https://pe0ples0ft.blogspot.com/2018/03/fluid-ui-click-to-call.html

      Delete
  18. Hi Sasank,

    Is there a way to reset a peoplesoft variable (e.g. global variable) using javascript.

    I am looking to reset some global variable (using windows.onbeforeunload) when the user changes the current window or closes it.

    Regards,
    Allen

    ReplyDelete
    Replies
    1. or maybe is there a way to reset the variable by triggering fieldchange event from javascript before window unloads?

      Delete
  19. Hi Sasank,


    We have One push button in PIA page, which was created by HTML Area Properties by using below code (Value - Constant and below are the code)

    tag- < or >

    tag a id="Left" class="PSPUSHBUTTON" style="background-Color: transparent;border:0;" tag
    tag span style="background-Color: transparent;" tag
    tag input id="#ICList" class="PSPUSHBUTTON" type="button" title="Return" alt="Return" psaccesskey="\" tabindex="5000" onclick="if (saveWarning('',null,'_self', 'javascript:submitAction_win0(document.win0, \'#ICList\')')) javascript:submitAction_win0(document.win0, '#ICList');" value="Return" name="#ICList" style="width:120px;" tag
    tag /span tag
    tag /a tag

    Functionality - It will take us to Search page when we click this "Return button"(Which was created by HTML Area). 9.1 and 8.52 it is working perfect.

    Issue- But there is no response when we click the "Return button " in 9.2 and 8.56.10 Environment.


    Do you have any idea that why its not working in 9.2/8.56.10 Env?

    Thanks,
    Madhan R

    ReplyDelete
    Replies
    1. You might want to review your browser console for errors. Let us know what you find.

      I apologize for the delayed response. I missed this comment.

      Delete
  20. I used this code and it seems to work well as long as the original button is on the page. However, if I try to use PeopleCode to make the button hidden (.visible = false) then my html link no longer works. If I use CSS to hide the button (psc_hidden), then it once again works ok. The reason I can't really do that though is because the button is in a grid and I don't want to have an empty column in the table.

    Am I missing something or do you need to have the original button on the page?

    Using Chrome ; PT 8.55 ; CS 9.2

    My one workaround is to use ONE button at level0 that I can hide with CSS and not mess up the page layout, then have another hidden field to store the "key" or row that I want to manipulate. I haven't tested this yet, but I think it should work. I would rather have the peoplecode on the actual FieldChange at the grid level.

    ReplyDelete
    Replies
    1. It would be great if you can explain what you are trying to achieve with this javascript on the page?

      This post was written for the purposes of Classic. I would not recommend this approach for Fluid. There may be other options in Fluid like using AddOnLoadScript function, AddJavaScript function, field class JavaScriptEvents property, etc.

      https://docs.oracle.com/cd/E92519_02/pt856pbr3/eng/pt/tpcl/langref_PeopleCodeBuilt-inFunctionsAndLanguageConstructs_A.html#u930a7c2b-6051-4807-9568-40d310e5ae33
      https://docs.oracle.com/cd/E92519_02/pt856pbr3/eng/pt/tpcl/langref_PeopleCodeBuilt-inFunctionsAndLanguageConstructs_A.html#u8e1953bb-38f1-4df8-8f8f-184b90fee957
      https://docs.oracle.com/cd/E92519_02/pt856pbr3/eng/pt/tpcr/langref_FieldClassProperties-071490.html#u83fdf6a5-cde7-4295-b8d8-71115e609fdd

      Delete
  21. I am not sure if it is here , But I am sure you have done it..
    I have a lookup field that I want to leave the Validation alone but I want to call my own DoModule Component ... So I have Removed the Prompt from the display added my On lookup Icon to press. and lookup uses another controlled Lookup, But still leaves to Lookup on Field if some manually chnages...

    My Question . In classic , and Fluid (maybe eassier)
    On A Field how can I hide the Magning glass of the field and ( On a grid) merge field into one..

    So It looks like the same Lookup but uses my code in field change instead of Search process thru a view

    ReplyDelete