After figuring out how to launch ANY WebDynpro ABAP from within my HCM P&F form (HCM Processes & Forms: Adobe or WDA? Why not Adobe AND WDA!?!?!), my mind was spinning with new ideas of how to use this. I was thinking of all kinds of pop-ups I would launch to do complex tasks and then send the results back to the form….and it would be all “behind the scenes” outside of the HCM P&F process configuration and Adobe form scripting. Then I thought again…”outside of the HCM P&F process configuration…..what has irked me the most about HCM P&F configuration for all these many years?…..ah yes…..USER EVENTS!!!!!”.
I don’t think it is any secret if you have seen my other posts, blogs, etc, that I completely HATE the way SAP implemented “user events” in HCM P&F configuration. From my developer background, I envision “events” as being things I can subscribe a “listener” too and handle as I like….such as having my own method/service/operation “listen” for an event and then use whatever form fields I had for that method to handle it. In the HCM P&F world, this is NOT the case. From my perspective and opinion (and many others like me), it is completely “bass ackwards” (a more polite slang way to say it haha).
Skip this section if you don’t want to be thoroughly confused to the point of having your head explode
In HCM P&F configuration, you define a “user event” which you then assign a “field group(s)” to….which by the way, has NO link/meaning/reference to any field groups you defined when configuring your “backend services” which further confuses the issue much more than needed!!….and define how that “field group” will respond (either like the “initialize” or “check” events of HCM P&F). Next, in that field group you select all the “form fields” you want to handle in your “user event”. ..did you get that?!?! You pick FIELDS…not objects/methods/services that you want to “listen” for your event!!!…….Now the real fun happens when your user event is actually executed. Behind the scenes the HCM P&F engine goes through and looks at all the fields you assigned to your field group of your “user event”. Then it pretty much goes down the list of your backend services and looks for EACH field of the “user event” which backend service it is used in…like “here is field EMP_GROUP….where are ALL services that this EMP_GROUP field is used in?”. If used in the service, that service goes into the list of services to execute for the “user event”. The next “fun” part, it will keep looking at that service that was added and say “what other fields are used in that service? Oh….let me add those fields to my list of fields to inspect too!” (which causes BIG problems if you forgot to put those fields in your list of “user event” field group fields)….but then it goes looking for all services that use those “added” fields too. It continues down all the list of fields in it’s field group until it has all the services it found them in (and then deletes any duplicates in that list) before it finally goes does the services it made it’s own “list” of and executes each one. So your user event can end up calling any of your backend services that you might not intended them too. In the past, our workaround for this was the clever usage of extra “event” or “trigger” form scenario fields and “rules” so that only the backend services you wanted to be called would be called in your “user event”.
So the challenge was laid down….how can I replace configuration “user events” with some sort of “windowless WebDynpro ABAP”? It became a little coding competition between myself and a fellow code monkey friend, Philip Johnston (who had also worked on the “pop-up ANY WDA” solution with me) to see who could figure it out first.
My first thought was, “what if my WDA component was a simple “faceless” WDA?” (http://help.sap.com/saphelp_nw04s/helpdata/en/e0/202d4108f08739e10000000a1550b0/frameset.htm) I coded it up, but sadly, it wouldn’t work correctly. I could not get a way to set my form fields back without having a view to handle this in (almost as I had done before within the “even handler” of the “OK” button being clicked). I am sure if I spent more time, I could have found some direct ISR related classes to get the “handle” back to my form fields, but I found an easier way.
Before I go into detail of “how” this can be done, maybe it is best to show you. So if you remember the “test” HCM P&F process and Adobe form from my other blog (HCM Processes & Forms: Adobe or WDA? Why not Adobe AND WDA!?!?!), I simply added a new button to this which will “fire” our “windowless” WDA. Here is how our page looks as it first loads:
The user inputs some information in the first “edit” field.
Now the user clicks the “WDA No Pop Up” button. Behind the scenes our “event” is being handled. The user simply sees the “wait” animated image pop-up.
Now, our event has completed and control returns to the front end, Adobe form. As you see, our example “event” read in the user’s input in the first field and then passes back the concatenation of the user’s input with “<<<< WE SET THIS!!!”. We could do the same thing without an user clicking a button (for example, using some event on any form control like “exit” or “change” on an input box to “fire” a hidden button for us).
The first part is very similar to what I explained in the blog about popping up any WDA. We are just going to read a field(s) from the form, set our context as we like and then trigger a pop-up window. Our “Call Pop-Up” method looks like:
….and then we launch the actual pop-up window…well, we tell it too at least (haha)….
But now, how do I deal with this “window”?!?!?
The “magic” to this came about by my thinking of the problem in another way. I thought, “if I must trigger some kind of pop-up window in order to have my WDA view to send information back to the form, what if I just triggered the window to close itself somehow before the user ever sees it?” I first tried this in the component controller right after issueing the “window open” command, but that did not work. Next, I thought through the series of methods that get called via WDA’s “Phase Model” (http://help.sap.com/saphelp_nw04s/helpdata/en/d2/8acd409cc4dd50e10000000a1550b0/frameset.htm) I thought “Now if our pop-up window is going to then display our view, maybe I can catch it in the view?” Since the WDOINIT method of the view gets called to “initialize” anything before the “view” is actually displayed, I thought “this is it!”….I would make whatever field changes, checks, business logic there and then put in some code to auto-close the window…in essence, close the window before it ever gets rendered and displayed to the user.
Guess what…..it worked!!!!!
I know what you are thinking….”Chris, this is all nice and well, and your little test application is cute….but this isn’t really a production example”…well, how about this? Here is this idea implemented in a REAL world, working scenario. Just so you can see this (because of course since the “event” is behind the scenes), notice that we never leave the “edit” state (“check and send” button still there).
Here is config in HRASR_DT, so you see there are NO “user events” defined through HCM P&F”:
Here is the form…the user can hit the “search” button for a Job or type one in directly. In this case, they are going to manually (type it in the field) change this:
Now, upon leaving the field (tab out or mouse to the next field), our “event” is triggered and we have a nice message on the form to the user to let them know:
Now, we see the field is updated (the text for the Job was retrieved and we even did validations behind the scenes).
Now, we do the same for Cost Center….
Again, you see that we never left the “edit” step of our form. Our “eventing” happened all within the form using my “windowless WDA” method and not using “user events” through HCM P&F config.
Bye-Bye HCM P&F “user events”…..and good riddance! (haha)
By the way, I won that coding contest against Philip Johnston….he owes me some beer. haha
One last note…in our testing, Philip did discover a “bug” in our version in which continuous uses of the “pop up” event seemed to make our form fields passed to the ISR interface DOUBLE on EACH use….so it grew exponentially! The problem was found to be in the WDA component QISR_UI in it’s component controller method SET_EXTERNAL_DATA_TO_INPUT_P. After the loop, they left off the simple line:
delete adjacent duplicates from cr_model->external_data comparing fieldindex fieldname.
We added this in an “overwrite” enhancement of the whole method and it works perfectly well now.
As always…till next time….enjoy!