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,
- File Attachments
- Approval Workflow Engine
- 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.
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
- 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
- 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.
- 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
- Register the Application Package/Class Peoplecode as a service under,
PeopleTools>Portal>Related Content Service>Define Related Content Service
- 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.
- 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;
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
LikeLiked by 1 person
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
LikeLike
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);
LikeLike
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.)
LikeLike
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
LikeLike
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.
LikeLike
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.
LikeLike
Hi Swati,
It is not mandatory to use event mapping, direct peoplecode on the record field will work.
LikeLike
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.
LikeLike
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
LikeLike
Hi Junaid, I have now added a functioning peoplecode as a sample in the blog post itself.
LikeLiked by 1 person
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
LikeLike
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
LikeLike
Hi Logesh,
Thanks for replying – we are on PeopleTools 8.57.05 and HCM PUM30.
Regards,
Anthony
LikeLike
In PT 8.56 and above map the related event people code on Page activate event, post execution of delivered code, instead of Component Post Build event.
LikeLiked by 1 person
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
LikeLike
Hi Anthony, What PeopleTools version are you on?
LikeLike
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.
LikeLike
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);
LikeLike
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
LikeLike
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.
LikeLike
Hi Ganesh,
Is your event mapping peoplecode firing POST the delivered Page Activate Peoplecode?
LikeLike
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.
LikeLike
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.
LikeLike
Hi Tom, Very thoughtful feedback, I reviewed your idea in idea spaces and agree with your suggestion and have voted it up.
LikeLike
Can I get a copy of the application package class code. Very much appreciated. Send to kathyjohnson@bc.com
LikeLike
Can I also ask for a full copy of the application package class codes? Please send it to debalicantelopez@gmail.com
LikeLike
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.
LikeLike
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!
LikeLike
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!
LikeLike
Hi Kuldeep,
Can you email me a copy of your app package code, so i can check it out? Please send it to logeshc@gmail.com
LikeLike
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
LikeLiked by 1 person
Hi Rajesh, certainly both can be achieved. Event Mapping Framework allows multiple events to be mapped to the same event and you can sequence the execution order.
LikeLike
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
LikeLike
Pingback: #89 – Gotchas
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
LikeLike
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.
LikeLike