Submit from jQuery modal causing session state protection violation

Don’t you hate those nagging issues where you attempt a few fixes in vain, waste hours of your life, and then suddenly the issue just resolves itself? What’s worse than an issue that won’t go away is one that just resolves itself and you don’t know why. You don’t know if it is just hiding, waiting to reappear at some inconvenient time later (e.g. when the app goes live in Production).

I added the first modal popup on a page in my application running on APEX 4.2.4 and immediately hit the problem described here: Jquery modal causing page protection violation error.

I’d used the simple popup modal using the builtin jQuery dialog widget as described here: Oracle APEX 4.2 – Creating a modal window [link no longer valid –] – Helen’s example works but doesn’t include submitting the page. Side note: I found it only worked if I put it in one of the page body regions, not in the After Header region.

The purpose of my popup is to accept additional input from the user, then submit the page. If I removed the page submit, the popup worked fine. On submit, it raises this error for the first item on the page:

“Session state protection violation: This may be caused by manual alteration of protected page item P1_ID. …”

If I turn off session state protection on the item, the same error is then raised on the next item on the page. Plus, I require session state protection to be enabled so disabling it is not an acceptable solution.

I didn’t want to import another plugin to the application because I wanted to keep it dead simple. The default jQuery dialog should just work, dammit! (I don’t mind importing plugins if the plain vanilla features provided by APEX are just not sufficient for the need; but the basic jQuery dialog is perfectly fine.)

In the end on a hunch I tried doing the submit after a timeout, i.e. instead of:

function popupSubmit() {

I changed it to:

function popupSubmit() {
  setTimeout( function() { doSubmit('SAVE'); }, 1);

This workaround seemed to have done the trick, but I wasn’t happy – it just felt “hacky”.

I tried adding a similar popup to another page that was far simpler and it didn’t experience the problem. So submitting from a popup dialog should work.

I reverted the code to remove the timout and tried disabling all the Dynamic Actions on the original page, and the problem disappeared. So I figured the problem was caused by some interaction with a Dynamic Action. I gradually re-enabled the DAs one by one, retesting the page between each one. Finally I re-enabled the last Dynamic Action – and the problem still didn’t reoccur. So the problem has resolved itself, but apparently not because of any particular thing I’ve fixed, and I can no longer reproduce the problem. Aarrgh.

UPDATE 4/9/2015:

After a number of unrelated changes to the page, I started getting this error again, consistently. As the comments (see below) suggested, this is due to the jQuery dialog.close() method moving its contents outside of the <form> tag, which meant that the items submitted to APEX differed from those in the original page, causing APEX to raise the error.

I could find no way of avoiding the error, so instead I’ve fixed it by a little hack: instead of opening the dialog based on the original region that was generated by APEX, I use jQuery to create a copy of the region, and open and close that copy. That way, the original region stays unmodified (forever hidden) and the page submit works. It’s a bit fiddly but it seems to work so far.

(in this example, P1_REAL_NOTE is the database item; P1_POPUP_NOTE is a non-database textarea that’s rendered in the popup region)

function showPopup() {
  //copy the current note text into the popup window

  //make a temporary copy of the region
  //(because dialog.close moves it leading to
  var x = $("#myPopup").clone();
  //change the ID of the copied popup note item
  $("#myPopupCopy textarea#P1_POPUP_NOTE")

  //popup the dialog
    ,title:'Please enter your Notes'
function popupSubmit() {
  //copy the note text back into the real form item

  //close the popup (this moves the contents out of the
  //form tag which is what was leading to the apex error)


Show an animated “Please wait” indicator after page submit

My application normally responds to button clicks with sub-second performance, but there were a few operations where users can initiate quite long-running transactions (e.g. up to 15 seconds long in one case where it was hitting an eBus interface thousands of times).

When the user clicks the button, I want the page to show a “Please Wait” message with an animated running indicator (I won’t call it a “progress bar” even though it looks like one, because it doesn’t really show progress, it just rotates forever) until the page request returns.


To do this I added the following to my application, based largely on this helpful article.

1. Add an HTML region on Page 0 (so it gets rendered on every page) at Before Footer, with:

<div id="runningindicator">
Processing, please wait...
<div id="runningindicator-img"></div>

2. Add the following to the global CSS file for my application:

div#runningindicator {
  display: none;
  background-color: #FFF;
  padding: 30px;
  border: 1px solid;
  border-color: #CCC;
  box-shadow: 2px 2px 2px #AAA;
  border-radius: 4px;
  position: absolute;
  top: 100px;
  left: 50%;
  margin-left: -110px;  /* the half of the width */
div#runningindicator-img {
  background-image: url(/i/processing3.gif);
  background-repeat: no-repeat;
  width: 220px;  /* the exact width of the image */
  height: 19px;  /* the exact height of the image */

3. Add the following to the global javascript file for my application:

function run_long_request (request, warnmsg) {
  if (!warnmsg || confirm(warnmsg)) {
    // disable all buttons on the page
    var btns = $("a[role='button']");
    $x_disableItem(btns, true);

4. Change the button:

Action = Redirect to URL
URL Target =

  'Are you sure you wish to approve this transaction?');

When clicked, the button runs my javascript function which first prompts the user to confirm, and if they do, it disables all the buttons on the page, shows the running indicator, and submits the request (which might be the name of the button, for example).

If I omit the second parameter, the function skips the confirm popup and submits straight away.

Known Issue: the animated gif doesn’t seem to animate in IE8. So far I haven’t worked out how to solve this, except to burn IE8 with fire and extreme prejudice. I’ve tried using setTimeout to delay showing the div but it stubbornly stays frozen.

EDIT: thanks to Peter Raganitsch who alerted me to a simpler option, that doesn’t need the region or the CSS, and animates in IE8:

function run_long_request (request, warnmsg) {
  if (!warnmsg || confirm(warnmsg)) {

Mind you, building this sort of thing from scratch was a useful exercise to learn the CSS and javascript tricks necessary. And another thing re-learned: there’s almost always a simpler way.

Add a Dynamic Total to a Tabular Report

I have a Tabular Report with an editable Amount item. When the page loads, the total amount should be shown below the report; and if the user updates any amount on any row, the total amount should be updated automatically.

Note: this method does not work if you have a tabular report that might have a very large number of records (as it relies on all records being rendered in the page at one time).

1. Make sure the report always shows all the records. To do this, set the Number of Rows and the Maximum Row Count to a large number (e.g. 1000).

2. Add an item to show the total, e.g. P1_TOTAL_AMOUNT. I use a Number field, and add “disabled=true” to the HTML Form Element Attributes so that the user won’t change it.

3. Examine the generated HTML to see what ID is given to the amount fields in the tabular report. In my case, the amount field is rendered with input items with name “f04” and id “f04_0001”, “f04_0002”, etc.

4. Add the following code to the page’s Function and Global Variable Declaration:

function UpdateTotal () {
  var t = 0;
  $("input[name='f04']").each(function() {
    t += parseFloat($(this).val().replace(/,/g,''))||0;

This strips out any commas from the amounts before parsing them as Floats and adding them to a running total; it finally formats the total using my formatMoney function and updates the total amount item.

5. Add the following to the page’s Execute when Page Loads:


To prime the total amount field when the page is loaded, I have a Before Header process that calculates the total based on a simple query on the table.

Now, in my case I want to have two running totals: one for “Cash” lines and another for “Salary” lines. My tabular report renders a radio button on each record which the user can select “Cash” or “Salary”. So instead of just the one total amount field, I have two: P1_TOTAL_CASH and P1_TOTAL_SALARY. The radio buttons have hidden input items with the value, rendered with id “f05_nnnn” (where nnnn is the row number).

My UpdateTotal function therefore looks like this:

function UpdateTotals () {
  var sal = 0, cash = 0, amt, rownum, linetype;
  $("input[name='f04']").each(function() {
    amt = parseFloat($(this).val().replace(/,/g,''))||0;
    // determine if this is a Cash or Salary line
    rownum = $(this).prop("id").split("_")[1];
    linetype = $("input[id='f05_"+rownum+"']").val();
    if (linetype == "SALARY") {
      sal += amt;
    } else if (linetype == "CASH") {
      cash += amt;

And my Execute when Page Loads has an additional call:


Now, when the user changes the amounts or changes the line type, the totals are updated dynamically.

EDIT: simplified jquery selectors based on Tom’s feedback (see comments) and use the hidden field for the radio buttons instead of querying for “checked”


UPDATE: If the tabular form has an “Add Row” button, the above code won’t work on the newly added rows. In this case, the Execute when Page Load should be this instead:

$(document).on("change", "input[name='f05']", function(){UpdateTotals();});

Show/Hide Multi-row Delete button for a Tabular Report

I have a standard tabular report with checkboxes on each row, and a multi-record delete button called MULTI_ROW_DELETE.

If the user clicks the button before selecting any records (or if there are no records), they get an error message. Instead, I’d rather hide the button and only show it when they have selected one or more records.


To do this:

1. Edit the MULTI_ROW_DELETE button to have a Static ID (e.g. “MULTI_ROW_DELETE”).

2. Add this function to the page’s Function and Global Variable Declaration:

function ShowHideMultiRowDelete () {
  if ($("input[id^='f01_']:checked").length==0) {
  } else {

This looks to see if there are any checkboxes selected, if none are found it hides the delete button, otherwise it shows it.

3. Add this code to the page’s Execute when Page Loads:


This does the initial check on form load (i.e. it initially hides the button, since none of the checkboxes will be selected yet), and adds a listener to the checkboxes so that if any of them are changed, the function is re-run to show or hide the button as needed.

Unfortunately this doesn’t work with the “all rows” checkbox that was generated by the tabular report, so I’ve added a step to hide that checkbox (“check-all-rows”) until I can find a solution for that.

Autoformat ANY amount item, anywhere

If you’re building a “finance-ey” application you probably have plenty of fields that should show and accept monetary amounts – and quite possibly these items may be implemented in a variety of ways – ordinary apex number items, edit fields in tabular reports, or even dynamically generated items using APEX_ITEM.text.

In my case I had all three, scattered throughout the application. Our users routinely deal with multi-million dollar amounts and they had trouble checking the amounts visually, especially when there are a lot of zeros, e.g. “10000010.00” – so they asked for them all to be formatted with commas, e.g. “10,000,010.00”.

Step 1. SQL number format

So in my first release of the apex application I applied the “FM999G999G999G999G990D00” format to all the money amount items, including in reports etc. The users were reasonably happy with this, but thought it wasn’t working in all cases – e.g. they’d type in a new amount, and the item wouldn’t get formatted until after they Saved the record. This is because the format is only applied when the APEX rendering engine is formatting the page for display – it doesn’t apply it dynamically as the items are changed.

Step 2. Dynamic Actions using SQL

So I started adding dynamic actions to all the apex items which would call the database to format the amount every time the item was changed. This was ok, but performance wasn’t that great – there was a visible sub-second delay while the page did an ajax call to the database just to do the formatting.

Step 3. Dynamic Actions using Javascript

So then I found a Javascript money formatter and modified my dynamic actions to call that instead. The only downside is that it is not internationally-aware. In my case this application’s target users are all here in Australia, are in the education industry, and they haven’t complained about the lack of international money-formatting support (yet).

Number.prototype.formatMoney = function(decPlaces, thouSep, decSep) {
  var n         = this
     ,decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces
     ,decSep    = decSep == undefined ? "." : decSep
     ,thouSep   = thouSep == undefined ? "," : thouSep
     ,sign      = n < 0 ? "-" : ""
     ,i         = parseInt(n = Math.abs(+n || 0).toFixed(decPlaces)) + ""
     ,j         = (j = i.length) > 3 ? j % 3 : 0;
  return sign
    + (j ? i.substr(0, j) + thouSep : "")
    + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thouSep)
    + (decPlaces ? decSep + Math.abs(n - i).toFixed(decPlaces).slice(2) : "");

That worked really well, there was no visible delay, and the users were pleased. But I wasn’t satisfied – this trick doesn’t work on the tabular reports or on my APEX_ITEM-generated items.

Step 4. jQuery to the rescue!

So I’ve gone back to the drawing table and decided that I don’t want to have to add Dynamic Actions to each and every item that needs it, which doesn’t work for the items that are generated dynamically (e.g. when the user adds a record to a tabular report). This formatting should be applied automatically to each item, and the only thing I’m going to add to each item is a CSS class. I needed to use some jquery to dynamically bind some javascript to every item that has a particular class, even if the item is added after the page has loaded.

This stackoverflow question came in useful. I added the following to my global javascript file:

$(document).ready(function() {
  $( document ).on('change', '.edit_money', function(){
    var i = "#"+$(this).attr("id")
       ,v = parseFloat($(i).val().replace(/,/g,''))||0;
    $(i).val( v.formatMoney() );

All I have to do is add the “edit_money” class to all my money items. For ordinary Apex items, you put the class in the HTML Form Element CSS Classes attribute. For items in a tabular report, the same attribute is under Column Attributes, called Element CSS Classes.

For items generated using APEX_ITEM, I just had to add some extra parameters (p_attributes and p_item_id), e.g.

  (p_idx        => 2
  ,p_size       => 16
  ,p_maxlength  => 22
  ,p_attributes => 'class="edit_money" style="text-align:right"'
  ,p_item_id    => 'f02_'||TO_CHAR(ROWNUM,'fm0000')

So, that was a reasonably good couple of hour’s work, I think. I’m not the world’s expect on javascript or jquery by any stretch of the imagination, but I’m quite happy with the result so far. I’m sure there are even better ways of doing this, so if you know of a better way please comment.

APEX: Save a user’s checkbox selection on local PC

You want a checkbox item on a page which is a preference, you want it to be remembered for the user across login sessions, but you don’t want the overhead of storing it in a database table. You might choose to store the value in a cookie instead. It may be lost (e.g. when the user clears their cookies or changes to a different browser or another computer), but we don’t mind – it’s just a preference.


1. Create checkbox item, e.g. P1_STAY_ON_PAGE

Display As = Checkbox
Template = No Label
List of values definition = STATIC2:Stay on page;Y

2. Add dynamic action to the checkbox item to save it when it’s changed

Event = Change
Selection Type = Item(s)
Item(s) = P1_STAY_ON_PAGE
Condition = (none)
True Action = Execute JavaScript Code
Fire On Page Load = (No)
Code = SetCookie("APEX_P1_STAY_ON_PAGE",$v("P1_STAY_ON_PAGE"));

3. Add dynamic action on page load to load it

Event = Page Load
True Action = Execute JavaScript Code
Code = $s("P1_STAY_ON_PAGE",GetCookie("APEX_P1_STAY_ON_PAGE"));

Note that the cookie name (“APEX_P1_STAY_ON_PAGE” in this example) is up to you to choose. Probably best to try making it specific to your application so it doesn’t clash with anything else.

Too Much Validation is Too Much

I had built and was managing a web site that takes registrations from thousands of people around the state for a variety of sporting events. One of the goals of the site is to collect better quality data for the people running the events, i.e. they basically needed to get a better handle on how many people were actually attending.

One of the other goals of the site was to make it as easy and hassle-free as possible for anyone to register. This meant that requiring people to sign up for an account with usernames and passwords was undesirable, so make it possible for someone to just sign up with all their info in one session (i.e. never authenticated), then never return.

This also meant that if someone started to register one day, but abandoned their “shopping cart” (so to speak), and then came back the next day, they happily re-entered all their info again – which caused duplicate records to appear in the database. Someone accidentally closes their browser – another duplicate record. Someone signs up their friend on their behalf, not knowing their friend had already signed up – another duplicate record. Someone with very little computer experience gets an error (e.g. “Date of birth must be entered.”) and responds by closing the browser and restarting – and doing this multiple times – we got five duplicate records from this person.

So I built an automated alert system which would email the team coordinators a list of the duplicate records, based on a simple case-insensitive match on first name + surname (we did have one case last year where two different people happened to have the same name, but this is a very rare occurrence when you’re talking about only a few thousand people). I also built a de-duplicator which allowed me to compare two records side-by-side and delete one of them.

In the crunch week (the week before nominations close), we were getting 40+ registrations per day – and each day I was deleting 4 or 5 duplicate records. I thought there must be a better way.

So I (naïvely) quietly added a simple validation check to the signup page – if the player’s name was already registered it showed the error message “Sorry, a registration under you name has already been created. Please login to change your registration.” along with my contact details.

usererrorIt worked, kind of – immediately I got 3 emails and 1 phone call from people who had started their signup, having earlier ignored or missed the email with their login details, and tried to sign up again. I made sure they could login, and they were able to update their existing registration without creating duplicate records. I was quietly optimistic that it would work better now.

Unfortunately, I was wrong. A few days later (today, actually) I decided to do an audit to see if my change had actually made things better or not. I suspected that some people might ignore that error message and just put in a different name. My suspicion was warranted, as it turns out.

So far I’ve gone through over 800 records and found variances of “Bloggs, Joe” or “Bloggs, Joe B” or “Bloggso, Joe” or “Bloggs Is My Name, Joe” scattered throughout. All my validation had done was put a roadblock in front of the users, who simply drove around it by putting in a slightly different name (I saw a lot of them simply put in their middle name), and now (more importantly) my de-duplicator is useless because it only finds matches on exact given names and surnames.

I’ve removed the validation. The duplicate records are manageable, and the system is overall easier for everyone with less validation.

Grassroots on APEX 5

Scott Wesley has started an excellent series of posts exploring the Early Adopter release of APEX 5.0 [].apex5

I’m excited about the changes in 5.0 but have been too busy both at work and at home to look into it personally – so for now reading other people’s reviews has had to suffice. I’m looking forward to hopefully hearing more about it at AUSOUG later this year.

My advice is, have a look and give it a go sometime. In other words, do as I say, not as I do 🙂

Don’t mess with my page, bro

One of my clients reported an issue – they were seeing “Waiting for” and a blank screen when they tried to access the Apex web site I’d built for them. They were using Mozilla on a Windows PC, connecting via Vodaphone 3G – the problem was consistent, and it went away when they used their ADSL connection.

My initial response was “don’t use Vodaphone 3G” because the problem seemed to be outside of my area.  It appears to be a common issue, something that some mobile operators do to reduce image sizes – c.f.  and

My client did a little more digging (he’s a techie as well) and found this:

After reading that I said I’d give it another go and see what could be done. As far as I could see, the only really viable solution is to add the “Cache-Control: no-transform” header to the responses. Since I’m using Apache, to do this I added the following to my apache config as per

Header merge Cache-Control no-transform

That seemed to fix the problem. What this header does is instruct all intermediaries to not modify the content in any way – i.e. don’t try to recompress the images, don’t inject any extra CSS or javascript into the page, nothing. Adding this header does carry the risk that performance on some mobile networks may suffer (because they will no longer do the image compression), so it’s now up to me to make sure my pages and images are as small as possible.

Don’t (always) call v()

Instead of calling a function, when you can get the same effect by accessing a documented PL/SQL variable, you should. For example:

v('REQUEST')     = APEX_APPLICATION.g_request
v('APP_ID')      = APEX_APPLICATION.g_flow_id
v('APP_PAGE_ID') = APEX_APPLICATION.g_flow_step_id
v('DEBUG')       = APEX_APPLICATION.g_debug

(Note – g_debug is a boolean, unlike the v() equivalent)

UPDATE: If you’re using APEX 5, you can now get the User and Session ID from the APEX$SESSION application context.

There’s more here: documentation for the APEX_APPLICATION package

I suspect that the implementation of v() is something like this [EDIT: read the comments for more commentary on this, and a more accurate picture of what v() actually does]:

  res VARCHAR2(4000);
  CASE p_name
    res := APEX_APPLICATION.g_flow_id;
    res := APEX_APPLICATION.g_user;
      res := 'YES';
      res := 'NO';
    END IF;
    res := APEX_APPLICATION.g_request;
  ... etc. ...
      SELECT s.item_value
      INTO res
      FROM wwv_<session-values-or-something> s
      WHERE s.item_name = p_name
      AND s.flow_id = APEX_APPLICATION.g_flow_id
      AND s.session_id = APEX_APPLICATION.g_instance;
        RETURN NULL;
  RETURN res;
END v;

In addition, instead of calling v('APP_SESSION') / v('SESSION'), you could call the undocumented function APEX_APPLICATION.get_session_id instead, which is probably faster, or refer to the global variable APEX_APPLICATION.g_instance instead. I would suspect that the function normally just returns g_instance anyway, but it’s possible there’s some more logic behind the function.

Disclaimer: use undocumented bits at your own risk.

Some other undocumented goodies that may be useful include (and a lot of these are not available at all via v()):

APEX_APPLICATION.g_flow_alias = application alias
APEX_APPLICATION.g_flow_name = application name
APEX_APPLICATION.g_flow_version = application version string
APEX_APPLICATION.g_flow_status = app availability status code, e.g. AVAILABLE_W_EDIT_LINK
APEX_APPLICATION.g_build_status = app build status code, e.g. RUN_AND_BUILD
APEX_APPLICATION.g_base_href = the base URL for the site, not including the f?p=... bit
APEX_APPLICATION.g_printer_friendly = TRUE if the page was requested with Printer Friendly flag
APEX_APPLICATION.g_excel_format = TRUE if the page’s report is being rendered in CSV format
APEX_APPLICATION.g_date_format = Application default date format
APEX_APPLICATION.g_date_time_format = Application date time format
APEX_APPLICATION.g_timestamp_format = Application default timestamp format
APEX_APPLICATION.g_timestamp_tz_format = Application default timestamp with time zone format

You can have a peek at all the globals in this package with this query (but be warned, any undocumented ones may change, and may not necessarily be set to any meaningful value when your code is running):

select owner, trim(text)
from dba_source
where name = 'WWV_FLOW'
and type = 'PACKAGE'
and ltrim(text) like 'g%'
order by owner desc, line;