Enhancing Fluid Forms with PeopleCode Event Mapping

Fluid Forms and Approval Builder is a handy utility that provides an alternative to paper based processes in a organization. It’s key features are the out-of-the-box integration with,

  1. File Attachments
  2. Approval Workflow Engine
  3. Component Interface Mapping

It is ideally suitable for building simple forms, collecting file attachments from users, invoking workflow approval process involving multiple users and finally updating a transaction component using component interface.

However a common feedback among customers is that this utility is too simple and not effective to build user friendly forms for real-world use-cases. Key limitations of this utility are,

  • Inability to default or load contextual data to the form
  • Inability to validate data entered by user
  • Lack of support for multiple levels of data (table structures)

While this utility is not intended to build complex pages like application designer, basic features like field defaults and validations are essential to build user-friendly forms.

Thanks to the ever so powerful PeopleCode Event Mapping feature. We can now effectively introduce custom business rules and validations to the forms built using Forms and Approval builder.

 

FluidForms

I have illustrated this capability using a simple form created for employees to claim expenses.

  • A fluid form is created using Forms and Approval builder, making use of the delivered attachment and workflow approval capability
  • PeopleCode Event Mapping Framework is used to
    • Pre-Populate form  with employee related information
    • Validate data entered by user when the form is saved, allowing the user to resolve any validation error

Designing and deploying a form using Forms and Approval builder is entirely an online configuration activity, using PeopleCode event mapping framework to build and add business rules to the forms is a technical activity.

Explained below is the summary of steps to build a form as shown in the video.

  • Use Form Designer utility to build and deploy a fluid form, making use of the full set of features like file attachments, workflow approvals, security

FluidForms1

  • Deployed form can be added to a Fluid Homepage
    • Optionally you can set a image for the tile
    • When the form is accessed, initial component that is loaded – EOFM_CONTAINER_FL. This component basically acts as an index listing the forms already created and allows user to create a new form

FluidForms6

  • When user clicks to fill a new form, the form layout page opens, notice the Fluid Component for this page is – EOFM_FORM_FL. This is the component to which the Peoplecode needs to be mapped.

FluidForms7

  • Create an application package and class that contains the Peoplecode to execute your business rules. Record/Fields associated with the Form data elements can be figured out by reviewing the structure of the component – EOFM_FORM_FL

FluidForms3

  • Register the Application Package/Class Peoplecode as a service under,

PeopleTools>Portal>Related Content Service>Define Related Content Service

FluidForms4

  • Associate this new service to the target forms component under,

PeopleTools>Portal>Related Content Service>Manage Related Content Service

Note: Component – EOFM_FORM_FL as delivered is not available on the portal registry, so this has to be first registered in the portal, so that related events can be mapped.

FluidForms5

  • Test the functionality to suit your requirements

Note:

Peoplecode event mapping framework in PeopleTools 8.55 has capability to inject custom Peoplecode into component and component record field level events. This functionality is further enhanced in PeopleTools 8.56 providing more Peoplecode events such as page activate etc.

Update May 2019:

If you are PeopleTools version 8.56+, map the App Package Peoplecode to ‘Post Page Activate’ in the event mapping framework. So your code gets executed last.

Value defaulted to form fields only get saved, only when “&c_sdcontroller.updateField…..” gets executed for each value assignment.

Below is working code to pre-populate a form with a list of default value. In this example a list of direct reports are defaulted for a specific manager id.

import PT_RCF:ServiceInterface;
import FS_SD:Runtime:Controllers:*;

class SetFormData implements PT_RCF:ServiceInterface
   method execute();
end-class;

Component FS_SD:Runtime:Controllers:SDRuntimeController &c_sdcontroller;
Component FS_SD:Runtime:Controllers:SDSearchController &c_objSDSearchController;

method execute
   /+ Extends/implements PT_RCF:ServiceInterface.execute +/
   Local Rowset &rsFormDataLvl1, &rsFormDataLvl2, &rsDirectRpts;
   Local string &strLabelFldNm, &strAssgnmntFldNm;
   Local number &i, &j, &k;
   &rsDirectRpts = CreateRowset(Record.POIT_FORM_DIR_V);
   &rsDirectRpts.Fill("WHERE SUPERVISOR_ID=:1", %EmployeeId);
   
   If GetLevel0()(1).FORM.FORM_TYPE.Value = "XXXXXXXXX" And
         GetLevel0()(1).FORM.FORM_APPR_STATUS.Value <> "A" Then
      &rsFormDataLvl1 = GetLevel0()(1).GetRowset(Scroll.FS_SD_RT_GRP_VW);
      For &i = 1 To &rsFormDataLvl1.ActiveRowCount
         &rsFormDataLvl2 = &rsFormDataLvl1(&i).GetRowset(Scroll.FS_SD_RT_GLC_VW);
         For &j = 1 To &rsFormDataLvl2.ActiveRowCount
            For &k = 1 To &rsDirectRpts.ActiveRowCount;               
               &strLabelFldNm = "EMPLOYEE ID" | &k;
               If &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_FLDNAME.Value = &strLabelFldNm Then
                  &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_FLDNAME.Value, &strAssgnmntFldNm);
                  &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_TEXT5_2.Value = &rsDirectRpts(&k).POIT_FORM_DIR_V.EMPLID.Value;
                  &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_TEXT5_2.DisplayOnly = True;              
                  &c_sdcontroller.updateField(&rsFormDataLvl2(&j), &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_TEXT5_2);
                  Break;
               End-If;
               &strLabelFldNm = "NAME" | &k;
               If &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_FLDNAME.Value = &strLabelFldNm Then
                  &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_TEXT30_1.Value = &rsDirectRpts(&k).POIT_FORM_DIR_V.GetField(@("Field.NAME")).Value;
                  &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_TEXT30_1.DisplayOnly = True;
                  &c_sdcontroller.updateField(&rsFormDataLvl2(&j), &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_TEXT30_1);
                  Break;
               End-If;
               &strLabelFldNm = "JOB TITLE" | &k;
               If &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_FLDNAME.Value = &strLabelFldNm Then
                  &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_TEXT30_1.Value = &rsDirectRpts(&k).POIT_FORM_DIR_V.JOBTITLE.Value;
                  &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_TEXT30_1.DisplayOnly = True;
                  &c_sdcontroller.updateField(&rsFormDataLvl2(&j), &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_TEXT30_1);
                  Break;
               End-If;
            End-For;
         End-For;
      End-For;
   End-If;
   
end-method;

 

 

 

37 thoughts on “Enhancing Fluid Forms with PeopleCode Event Mapping

  1. Hi Logesh/All,

    Is there a way we can push the attachment from Form to Component? The requirement is Users will upload the attachments while submitting the forms and once the form is approved data will be pushed to the Component using CI Mapping. But I am not getting how to push the attachment as well.
    Please help is anyone come across this scenario.

    Thanks,
    Jayant

    Liked by 1 person

  2. Hi Logesh,
    Great post! Your code works great to populate the default values to the form. But I also have a question: the event mapping code always executed twice when I add it to page activate postprocess. this causes problem when I tried to assign related actions because I need to use %Request.getparameter and the second time the event mapping triggered will overwrite those parameters. Could you give some advices? We are on PT8.57. Thanks a lot!
    –Dong Wang

    Like

  3. Component FS_SD:Runtime:Controllers:SDRuntimeController &c_sdcontroller;

    in my case this object(&c_sdcontroller) is null. How to get it fixed so that I can execute the follwoing line of code

    &c_sdcontroller.updateField(&rsFormDataLvl2(&j), &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_TEXT5_2);

    Like

  4. Hi – You all are much more technical than me but i thought I would go straight to the brain trust. We are trying to create a simple form to update the Job Data component in HCM via the CI mapping. I presume I need to get the key fields mapped: EmplID can come from the form, EmplRcd needs to be defaulted to 0, Effective date can come from the form, and Effective Sequence could be defaulted to zero. Any other data fields can come from the form. If my developer can get the 2 key fields to default, do you think the Form to CI Mapping will work for a Job Data update?
    Thank you for any input. I just want to know how much time and effort to spend on this or if Job Data is just too complicated for this functionality. (We have done the CI mapping for simpler components.)

    Like

    • Trish,
      CI Mapping can be used in the Add mode (as per the documentation), to create a new configuration value for the CI Mapping, It is not recommended for the updated. Even if it is possible for update mode, not recommend for the complex component like Job data.
      Instead of CI Mapping, you can write custom code to save post-change using the event mapping to trigger the code to do CI to Job data and handle the errors and issues accordingly.
      Regards,
      Ganesh A.M

      Like

    • CI Mapping update is not for a complex component in the update mode, Job data is a complex component.
      Based on the official documentation.
      Give it a try with simple transaction first.

      Like

  5. Hi Logesh,
    Very good Blog !! Thank you very much.
    My question is, do we have to use event mapping only for peoplecode to work on forms? I am trying to write a code on fieldchange event of FS_SD_RT_GLC_WK.SD_TEXT4_2 but the code is not triggered.
    I have tried record level code as well as component level code.
    Our requirement is to hide/unhide certain fields on the form based on the value selected on another toggle field. Can we achieve this? TIA.

    Like

  6. Your prompt response helped me save hours of unguided research.
    Thanks Logesh!
    I am currently exploring Form & App Builder functionality on FSCM 9.2 PUM 30, PT8.56. I had a lot of questions on it, few of which got answered.
    Posting them here, in case anybody needs to refer:
    1. Is there a way to delete a form definition, apart clearing from back-end tables?
    A- No, we can inactivate form definitions. But they’ll persist unless deleted from metadata records.
    2. Can we add static text/hyperlinks/in-line instructions to the form?
    A- No, we cannot add static text/hyperlinks/in-line instructions. The only method will be add text in 254 length fields, or to add form instructions (which are rather non-intuitive).
    3. Can we have dynamic prompts on form fields? Can we implement the related display fields?
    A- Need to explore if possible using event mapping. Seems like a difficult task to achieve.
    4. Is there a way to hide/disable the attachment button on form?
    A- Can be done using page/field configurator. But this configuration spans across all form definitions, not just a specific form definition.
    5. I encountered a bug in several delivered environments, wherein once I saved and activated a form, it throws page data inconsistency error on updating its layout again. Has anybody encountered this before?
    A- N/A
    6. Classic forms allow us to attach default documents like Terms and Conditions while defining them, but is it possible in Fluid forms?
    A- Fluid forms apparently lack such functionality.

    Like

  7. Hi Logesh,

    First of all, excellent post describing event mapping on forms.

    Secondly, like Ganesh, I too am facing issues invoking the sd runtime controller to update fields. I would appreciate some guidance here. Would you be able to share the updated code?

    Thanks,
    Junaid

    Like

  8. Logesh,

    Can you please share the full code of how you are able to save the defaulted values?

    I am getting the error First operand of . is NULL, so cannot access member updateField. (180,236).

    These are component variables and I declared it as Local, as I was not able to declare them as a component.

    Regards,
    Ganesh A.M

    Like

  9. Hi Logesh,
    Thankyou – you are a champion!!! Changing to Page Activate Event Mapping worked a treat and I now have the EMPLID being populated as your describe in your post.
    Regards,
    Anthony

    Like

  10. Hi Logesh,
    Thanks for replying – we are on PeopleTools 8.57.05 and HCM PUM30.
    Regards,
    Anthony

    Like

  11. Hi Logesh,
    Many thanks for this post.
    I have followed your example and created a simple fluid form with one text field however am not getting %EmployeeID being populated in FS_SD_RT_GLC_WK.SD_TEXT20_1 as you have shown. I have added a message in the PeopleCode which is appearing when I fill out a new form so the event mapping appears to be working.
    Any ideas as to what I may be missing in my PeopleCode?
    Regards,
    Anthony

    Like

  12. Lokesh,

    I am able poojate default values, based on the filed label I can identify the correct filed which needs to have the value.

    But when I save and submit the form, it is not saving the value to the database table while rest of the data values manually entered are save properly.

    Looks like that row is not marked changed and hence not stored to database.

    Like

    • Hi Ganesh,
      Yes, I too came across this item. Value assigned to the form fields is getting saved only when the Field change PC on the form fields get fired, because there is delivered code on these fields to assign the value to the correct DB table.
      So I had add couple of lines of Peoplecode to the app packages that was created for Event Mapping, to execute the same logic as field change code.

      import FS_SD:Runtime:Controllers:*;

      Component FS_SD:Runtime:Controllers:SDRuntimeController &c_sdcontroller;
      Component FS_SD:Runtime:Controllers:SDSearchController &c_objSDSearchController;

      &c_sdcontroller.updateField(&rsFormDataLvl2(&j), &rsFormDataLvl2(&j).FS_SD_RT_GLC_WK.SD_TEXT30_1);

      Like

  13. Nick,.
    Use formtype field to identify the form that your code needs to be enforced in the people code. Basically if condition identify when wich code needs to be excited.
    Regards,
    Ganesh A.M

    Like

  14. I am able to inject Peoplecode with Event Mapping in forms (class forms not fluid ) in 8.56 with page activate event mapping option, I am getting the Winmessage on the page activate of the form. I did not register the component, event mapping was done on new content reference created forms to be filled up by end users.

    But, I still have the issue of not able to make few fields disabled using this event mapping code.

    Any inputs will be appreciated, I know, that we can change the delivered page activate the code, but I want to avoid it.

    Like

      • Yes, it is. I have tried Post ‘Page Activate’, tried Post Component Post-build as well.
        What I have noticed it works fine for certain fields (I am able to default values and make it display only), but not for a few other fields.

        The field type that is used only once like TEXT10 field – then works fine.
        Field type that is used multiple times on the form will not work as if TEXT50 is used multiple times.
        I need to refer to this field as TEXT50 in the record (it doesn’t accept me to refer the field as TEXT50_1, TEXT50_2 – it gives me the error) even though it stores in the database field as TEXT50_1.

        All the fields of the same type on the page have the same field name (which we use field inspector to get the name of the field on the form page), not sure how to differentiate which field we are referring it, look like the system is confused as well.

        Like

  15. Hi Logesh.

    Thanks for the great article. I am using PeopleTools 8.56.09 and this worked perfectly.

    I’d point out for those that had troubles that a very important step is to register the EOFM_FORM_FL component as was pointed out in the article but could be easily glossed over. If you try to register your event against the published form, you will not be tying it to the correct component. I created a hidden folder and registered the component there.

    Another very interesting part of this was how we have to loop through each record and target the correct field for data placement. I used an Evaluate statement to evaluate the &j row number but maybe there is a better way.

    The only bummer was that due to how Fluid is typically deployed in multiple sub pages, those records and fields are not visible at the Component Record and Component Record Field Level Event Mapping. I created an Oracle Community Idea to see if we can get this fixed in some version. If anybody else knows of a way around this I’d love to hear it :).

    Here is my Idea link in case you want to vote it up 🙂 https://community.oracle.com/ideas/23455

    Thanks again.

    Tom Williams Jr.

    Like

  16. Hi, I was able to implement this and get the PC to pre-populate some fields. We are not using the Fluid page for this, just the standard forms component and have run into a couple of issues. First, for any fields that are required, the Component processor thinks that the fields are empty and gives an error saying the field is required. If I edit the field manually, then it will work but obviously that defeats the purpose. Second, I had to add this code to Page Activate as putting it in an App Package on PostBuild and using Event Manager did not work. As another user noted, there is delivered Page Activate code that wipes out any pre-populated data. We are on Tools 8.55. Any suggestions for how to get around these issues, particularly the first one? Thank you very much.

    Like

  17. Hey Guys,

    I figured it out why the changes were not reflecting on the page.
    Apparently there was some delivered code at page activate which was flushing out the changes.

    I just tried to modify the delivered page activate code and it worked fine!

    So to summarize currently there’s no provision in event mapping for page activate however in PT 8.56 they have provided this option so I need to wait till the tools upgrade 🙂

    Thanks!

    Like

  18. Hey Thanks for sharing!

    I actually tried this, however the values were not getting defaulted on the page. The code was triggering since I could see winmessages popped up however no values come on page.

    Any clue what could be wrong?
    Any inputs would be of great help!

    Thanks!

    Like

  19. Hi Logesh,
    When mapping Save post change event, so can we send notifications to people outside the form approval hierarchy. Also, can we add separate events for Save and Approval actions to trigger such savepostchange emails.
    Thanks,
    Rajesh

    Liked by 1 person

  20. Hi Logesh,

    Thank you for the explanation. We have a similar requirement and PS Forms were ruled out as they cannot handle defaults and validation logic. I am gonna give this a try now. We are on PT 8.55 and I hope it works as described in you article. Thank you!

    Vimal

    Like

  21. Pingback: #89 – Gotchas

  22. Hi Logesh,
    Thanks for the informative article – adding event driven logic to the forms makes them far more usable and powerful.

    Just a follow on question – if we are adding the PeopleCode event to the content reference, how is it able to distinguish between forms? i.e. If we have a Expense claim form and a New Supplier form, and want to have different logic to add defaults to them?

    Thanks,
    Nicholas Rule

    Like

    • Hi Nick,

      Very valid question. In the custom application class, we can add logic to distinguish the form. Record Field – PS_FORM.FORM_TYPE is available on the form and carries the form template id that the user is currently accessing E.g. Expense, Supplier etc.
      So custom logic to default fields etc, can check the Form Type and execute code specific to certain forms.

      Like

Comments are closed.