Understanding How PeopleCode Events Work
Understanding How PeopleCode Events Work
PeopleSoft comes with 17 events for PeopleCode. Each event has a specific function and
control for which it is designed.
Event Order
To best understand the PeopleSoft Panel Processor, consider the process of starting and
running a page to see when all the types of events are going to run.
First, the user selects from the menu to run a specific page in a certain action (this action
being Add, Update/Display, Update/Display All, or Correction). The Panel Processor
then looks at the menu selection to find the component connected with it. The component
contains the search record for the action in which the user has asked the system to run.
The search record keys, alternate keys, and list information are gathered from the search
record that has been assigned to the component. The search page is created online with
the keys and alternate keys displayed for entry, but before the user can enter any data, the
first event of PeopleCode activates.
SearchInit
After this code is complete, the user is able to interact with the search page to search
records and select the one they wish to process. Upon clicking OK in this search panel,
the next event becomes active.
SearchSave
If no error messages are encountered within the code, the main page, as requested from
the menu by the user, is now opened. Data, as selected from the search page, is then
ready to be loaded into the page. Before the data is actually loaded, each row of data that
is to be loaded onto the page is validated by the code contained in the next event.
RowSelect
The page is now filled with data from the search page, but the processor is not yet ready
for user input. A series of events must launch for each row of data already loaded into the
page.
If the user changes a field (modifies or deletes) or adds data to an empty field, the
following PeopleCode events run. Of course, the standard PeopleSoft record edits must
pass first, such as the prompt values as defined in the record definition for this field.
You will also note that some events of PeopleCode are running a lot of the time. You
need to understand the flow of the events so that when you have a function or code to add
to the system, you place the code in the correct event and therefore it runs at the
appropriate time to perform the correct action. You can place code in an incorrect event
so that it runs too much—this will affect your system by slowing it down.
SearchInit
The code in the SearchInit event is needed only for records that will be used as search
records. If the record definition you have is not used as a search record, then code placed
in here will never run.
Code placed in this event is typically used to set up default values on the search page. For
example, this event is mostly used to set up counters or defaults from the operator
preferences on the search panel. For example:
SetSearchEdit(BUSINESS_UNIT);
SetSearchDefault(BUSINESS_UNIT);
This example turns on edits and system defaults for the Business Unit field in the search
page. This code does not cause any other PeopleCode category to activate; it simply sets
up the information in the page object to be used in that specific field.
SearchSave
This code also applies to the search page and is typically used to validate the search page
to make sure all the required fields are filled in. Because you cannot specify the required
fields on a search record (the record definition's required attribute is for use only on the
regular pages), you can place code here to do the validation of all the fields that must be
filled in. For example:
If None(BUSINESS_UNIT) Then
End-If;
End-If;
check_auto_num(BUSINESS_UNIT, &AUTO_NUM);
If None(&AUTO_NUM) Then
End-If;
Error MsgGet(10200, 34, "This business unit is not set up for purchase order auto
numbering.");
End-If;
This example shows a little more about the capability of this event of code. The code
here, although complex for now basically checks that certain fields are filled in. If they
are filled in, then the data is validated for specific conditions. If an error condition exists,
an error message is displayed and the search page is not closed.
RowInit
Now you have arrived at events that are used more often in development projects. The
code in the RowInit event runs every time a new row of data loads into a page. This
section activates code for each level and each data row. For example, if you have a panel
with a level 1 that has 15 data rows that load, the RowInit event will run 16 times: once
for the level 0 (header information) and then 15 times for each row of data on level 1.
You need to understand that even though on the page you can see only five rows of data,
this code activates for all rows of data that are loaded into the buffer. So it is not how
many rows are visible on the page, but how many rows are loaded into the data buffer
that determines how many times this PeopleCode category activates. Consider the
following 3 examples:
If All(PO_ID) Then
VCHR_PANELS_WRK.TXN_CURRENCY_SRC = "P";
End-If;
End-If;
DERIVED.EDITTABLE13 = "ITM_PURCH_FS";
End-If;
Gray(LINE_NBR);
Gray(SCHED_NBR);
Gray(BUSINESS_UNIT_RECV);
These examples show different ways to use the RowInit event that are typically done.
The first example shows, based on some information, that you can set some values into
special fields. The second example shows that you can also set or change the prompts
used. Finally, the third example shows how you can override the settings on the page to
hide, gray (display-only), unhide, or ungray (not display-only) fields based on the
initialization.
FieldDefault
In this event, field defaults can be coded. This event works only to set defaults into fields
where the logic is too complex to use the record definition. If, by contrast, you have a
hard default that is always to be used, then you should set that value in the record
definition. Otherwise, you can set the default based on a condition check of some other
field or value using code from the FieldDefault event. For example:
FieldChange
The FieldChange event occurs under two circumstances: once when a field is changed,
and the other when a button is pressed.
For the field change event, the code does not execute unless there is a net change
(changing the value of a field to it's original value is not a net change) and the user moves
out of the field or saves the page. Here you can do very complex validation upon the
field.
You can also use the FieldChange event when you have a button on a panel; here you
would place the code that you wish to activate when the button is pressed. The code you
place for a button can be just about anything you want. This is what makes button actions
so powerful—they can perform all sorts of actions, controls, and verifications. When you
have a button and it is pressed, you are usually looking for some action to take place:
jump to another panel, fill in the current panel with data based on some criteria you have
set, or run a process, for example.
UnhideScroll(RECORD.PO_LINE);
UnGray(GOTO_LINE_DTLS);
SEL_LINE_FLG = "Y";
LINES_SAVED = "N";
If All(LINE_NBR_TO) Then
ScrollFlush(RECORD.PO_LINE);
This example is from a button which, when pressed, is going to fill in data based on some
criteria. The scroll, on level 1 in the panel, is un-hidden (now visible on the panel), and
the data buffer is emptied for this scroll (scroll flush). Finally, the scroll's data buffer is
filled with data based on a selection criterion.
FieldEdit
In the FieldEdit event, you apply most of the field editing to validate information within a
field. You already can do one simple validation using the prompts on a field as defined
within the record definition, but this event gives you the ability to validate using multiple
fields and conditions. This is also the event to apply messages from PeopleCode that will
not crash the panel, to warn or stop the process within the page.
The FieldEdit event is where you should place validation that you want to occur within
the page field entry process. If you have validations for which you do not want to leave
the field before a specific criteria or process is complete, then you need to place code in
FieldEdit. In this event, the action is based only on the field you are in, so be careful not
to validate against another field that you cannot change. If you do validate against
another field, you will be locked in a loop and you won't be able to leave this field.
To better explain this potential loop problem, assume that you have two fields on a panel.
The first field can be set to a value of Red or Blue only. The second field can be set to a
number that represents the brightness of the color (that is, the first field). Now red can
have a brightness only between 1 and 5, whereas blue can have a brightness between 3
and 9. So you place FieldEdit code in the first field (the color field) that states that if the
value is blue, then the value of the second field must be between 1 and 5. This meets the
logic requirement, but if you understand the FieldEdit process, you will see how this will
get you into trouble. The user enters Red into the first field and tabs out to the next field.
The PeopleSoft Panel Processor then runs the FieldEdit code for the field that states that
if the value is red (which is what the user entered), then the value of the next field must
be between 1 and 5. Because the user has not entered a value in the next field, the value is
initialized as 0. Therefore, this FieldEdit code fails and requires the user to input a value
that will not fail. Because you've allowed only red and blue, and neither is allowed to
have a 0 value, then the user can never leave this field. This is a simple explanation, but it
shows how you have to be careful when using FieldEdit code for validation using other
fields. You have to understand the capabilities of the system and how the rules will be
applied. In this example, the best solution is to change the location where the validation
code is placed. The validation code should be placed in the Field Edit event of the
brightness field, or it could be moved to the SaveEdit event (about which you have not
learned yet).
The way that PeopleSoft will pass or fail a validation is by issuing a message. If you fail
the validation, a message must be called. If you pass the validation, then no messages are
displayed. There are two types of messages: warning and error. Each is a message, but
they carry different levels of actions.
A warning message tells the user that they might not want to continue or to use this value
in the field. With a warning message, the user can decide to stop and fix the issue or
move on and ignore the message. A warning means that the value in this field is not
normal, but the user is still allowed to continue. An error message , on the other hand,
does not offer the user a choice; the user must stop and fix the problem. You should make
sure that all decisions to error or warn are well documented in the technical
documentation for your modification.
The following example shows how to use the FieldEdit to do complex validation with an
error message. If a problem occurs, issue an error message to the user stating the problem
and do not allow the process to continue until it is resolved.
check_item();
If None(PO_HDR.VENDOR_ID) Then
End-if;
FieldFormula
This event is typically reserved for custom-built functions. You have already learned
about the flow of how PeopleCode activates from the PeopleSoft Panel Processor and
that the process FieldFormula runs for all sorts of actions. You should not place any code
in this category except custom-built functions.
RowSelect
This event is used to filter data loaded into a scroll level. This is an advanced technique
that will not be covered in this book. Most developers who want to restrict rows of data
create a view to use on the page with the restriction in the SQL where clause. By using
this event, you can apply this restriction as you need to or you can even change the
criteria as the page is being created.
RowDelete
This event is used to activate code when a delete is performed for a row of data rather
than for only a single field. This delete can be on any level. The developer, when using
this code even, can control whether a row of data can be deleted by checking for
orphaned records or other required validations. The purpose of this code is to prevent
deletes unless a specific criterion has been met.
The process to show the pass or fail of the event is just like in the FieldEdit event. If you
failed the validation, pass a message. If you do not issue any messages, then the delete
process has passed the validation. This category can also use the warning and error
message commands: An error always fails; a warning reports an issue to the user.
RowInsert
In the RowInsert event, you apply code to inserts of new data rows. Data, when loaded
into the page, is validated through the RowInit event, but when you add a new record
(level 0) or a new row of information (level 1 through 3), there is no RowInit to activate
because it was not initiated into the panel. The RowInsert can and should perform the up-
front validations that you would have placed in RowInit for new data rows being added.
Note
As you can see, you might need to place the same code in the RowInit and RowInsert
categories. This is another reason for looking at code that you could place into functions
so that you do not end up copying the same code into multiple categories.
MERCHANDISE_AMT = VCHR_PANELS_WRK.VCHR_BALANCE_AMT;
VCHR_PANELS_WRK.LN_BALANCE_AMT = MERCHANDISE_AMT;
End-If;
This code checks a work record field for a specific status and then updates some fields
using information in some other work record fields. The process done here can be just
about anything you think of, from graying (display only) and hiding fields to doing
complex logic for recalculating a total.
SaveEdit
In the SaveEdit event, you place code that validates on a save. This is used for the final
validation of the record. Usually, you can do a lot of this validation in the FieldEdit
event, but you might want the user to do all the input they can and then do a check just
prior to the save. You might also have to validate multiple fields as a unit. It is hard to do
this within FieldEdit, so you can place the overall validation in this event instead.
A final use for the SaveEdit event occurs when the user does not tab through every field
so the FieldEdit code never activates. If you still need this validation, you will have to
add it to SaveEdit to be sure that the code does run.
As with the other edit events, you can prevent or just warn on a save when the validation
is incorrect. If you prevent, then the user is unable to save the panel. If you warn, then the
user can stop the save process and edit the problem or they can continue. The process is
the same regardless of whether you're using warning or error messages. Of course, no
message means that you have passed the SaveEdit validation.
Error MsgGet(7030, 49, "You must enter either a quantity on Voucher Line %1 when
distributing by quantity. Or you can delete the line.", VOUCHER_LINE_NUM);
Else
If None(MERCHANDISE_AMT) Then
Error MsgGet(7030, 49, "You must enter either a merchandise amount on Voucher Line
%1 when distributing by amount. Or you can delete the line.",
VOUCHER_LINE_NUM);
End-If;
End-If
This code checks some values in the fields and then, if certain conditions exist, an error
message is issued, preventing the save of this panel.
SavePreChange
In the SavePreChange event, you can place code to change or update the data tables prior
to the save being committed to the database. This is your last chance to make changes. In
your page, you are making changes, but these changes are loaded only into your panel
buffers. It is not until you save the record that the database is updated. Once the save is
started, the PeopleCode runs and does all its SaveEdit checks and then just prior to saving
the information to the database, this event occurs. This event enables you to do other
processes and update other rows of data, assuming that the process will complete.
The SavePreChange event, is used mostly to update hidden fields that need to be changed
or corrected based on user input just prior to saving. You do not do updates within
SaveEdit, as this is only supposed to be looking for errors. If you need to total a field in
level 1 and place the information in a header record (level 0), here is where you would
make the code work, since you do not want to update the header level field with every
row insert or field change on the level 1. This enables you to put code in one place, and it
runs doing the work just prior to the save.
Many developers will place SQLexec function calls in this category. SQLexec function
calls enable you to run a SQL statement directly so that you can update a related field that
is not within the page. You have to be aware that using SQL direct statements can lead
you into trouble. You must be sure that the record you are going to update or insert is not
any- where within the component. If any field of the record is on the component, then
you will receive an error: This panel has been updated by another user . This error
message is telling you that something happened to the data between the time you
retrieved the data and the time you saved it. Someone else grabbed the information and
changed it prior to your change committing it to the database. The problem occurred
because of your SQLexec—it ran and made an update to the database. The PeopleSoft
Panel Processor then tries to commit the rest of your changes and sees that someone else
(yes, even though the SQLexec came from your process, the processor sees this as
another user) has made a change, so your panel is not allowed to save. So be extra careful
when using SQL calls within the events.
End-For;
This code loops through all the rows of a level 1 panel and updates a value in a lower-
level scroll (level 2).
SavePostChange
In the SavePostChange event, you add code that you want to activate after the rows of
data have been saved to the database. Code placed here could be line totals and other
calculated fields. This is also where a lot of SQL execs are written and performed to
update other necessary fields.
End-If;
This code example shows that if the page is in Add mode and the vendor is set to a
special persistence, then the vendor status must be set back to inactive so that no further
POs can be used. This process is used on vendors that are set to one time use only. After
you use them on a PO , the status is set to inactive so that you do not use them again. You
can see in this example how you are updating the vendor based on an action in the PO
system.
Workflow
The workflow event is for the specific use of workflow. You need to put in specific code
here that updates the workflow records and processes. Workflow is beyond the scope of
this book.
Note
Application Engine and Business Components are specialized, advanced tools that are
not covered in this book. They are mentioned here so that you know about all the new
places to locate PeopleCode, but no further mention will be made.
The process of PeopleCode running on the system has already been mentioned, but what
happens when PeopleCode is encountered within the new areas such as pages and
components? Well, the same overall order still applies. For example, when a scroll level
has data loaded into it, the RowInit code runs for each row of data. Now you are only
adding a new level of complexity to RowInit: first, all the RowInit code runs from the
record definition, then all the page code RowInit activates, and finally the RowInit code
in the component area runs. So the overall flow of the code running through the events
stays the same, but now you have some new areas to run within each event.
Let's explore each new section of PeopleCode within the page and component, reviewing
why they would be used and what events are available.
PeopleCode in Pages
Why would you place code in a page versus a record definition? If you have code for a
RowInit-type function that you wish to have run only when you are accessing a specific
page, then you should place code in that page. This way, you do not need to write code to
retrieve the page name and then check whether you need to run this code.
This requirement to have code run when within a specific page is used all the time,
because if you include one field from a record, all the PeopleCode of the record loads
into the page and runs. You might have a page that is usually used for this record and you
hide this field until a specific action is done. Now, when you are in the other panel, the
code will run, but this field does not exist on the page because it is for a whole different
process. You would have had to retrieve a value for the page you are in to then see
whether you wish to run the code.
Now with the new capability in PeopleSoft 8.1, you can place code directly into the page
so that it will activate only when the page is accessed.
The event here is a new name called Activate. Although it is a new name, you can swap it
for RowInit. This is the only event available for the page; the code entered here is
associated with the page itself.
PeopleCode in Components
Because you could place code only in the Activate event within the panel, there was still
a need to place code so that it runs only when a specific page is running. PeopleSoft tools
developers created a new place to load PeopleCode within the component to solve this
problem. You now have access to many more events that run only when in a specific
component.
Within the component definition, you have access to the following events:
• SearchInit
• SearchSave
• RowInit
• RowSelect
• RowInsert
• RowDelete
• SaveEdit
• SavePreChange
• SavePostChange
• FieldChange
• FieldDefault
• PreBuild
• PostBuild
• SavePreChange
• SavePostChange
• Workflow
• FieldEdit
As you can see from the list, you have all the events—including two new ones: PreBuild
and PostBuild. The order of the events and how they activate is not changed within the
component. Having this new capability enables you to enter code into the component so
that the code will run only when this component is active.
Remembering the rule requiring all the PeopleCode of a record to be loaded, even when
using only one field on a page, let's see how you can save time and effort by using this
new capability. Instead of having to write code to check what component you are in for
every piece of PeopleCode you have in the record definition, you can place just the right
amount of code within the component PeopleCode events. This makes the PeopleCode
easier to write and much more efficient.
Usually, you enter all the PeopleCode into the record and field definition area, but now
you can enter the code into the component. Using the component PeopleCode events, it
gets a little more complex. You can enter code against the component itself, fields within
the component and, finally, records within the component.
PreBuild
The PreBuild event is specific to the component; this code runs prior to the component
being built. This is typically used to hide, unhide, gray, or ungray fields, or to set certain
values in the component.
PeopleCode within the component record gives you an opportunity to set variables that
can be used later by PeopleCode located in other events. PreBuild can also be used to
validate data in the search page just as is done in the SearchSave event. This event runs
right after the RowSelect event within the flow of PeopleCode.
PostBuild
The PostBuild event is specific to the component; this code runs after the component is
built. This is usually used to hide, unhide, gray, or ungray fields, or to set certain values
in the component. The event can be thought of just like the RowInit event as the data is
already loaded into the component. This even runs right after the RowInit even in the
PeopleCode flow.