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 – http://rowantraining.blogspot.com.au/2013/08/oracle-apex-42-creating-modal-window.html] – 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() {
  $("#myPopup").dialog('close');
  doSubmit('SAVE');
}

I changed it to:

function popupSubmit() {
  $("#myPopup").dialog('close');
  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
  $s("P1_POPUP_NOTE",$v("P1_REAL_NOTE"));

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

  //popup the dialog
  $("#myPopupCopy").dialog(
    {modal:true
    ,autoOpen:true
    ,title:'Please enter your Notes'
    ,width:'500px'
    }
  );
}
function popupSubmit() {
  //copy the note text back into the real form item
  $s("P1_REAL_NOTE",$v('P1_POPUP_NOTE_COPY'));

  //close the popup (this moves the contents out of the
  //form tag which is what was leading to the apex error)
  $("#myPopupCopy").dialog('close');

  apex.submit({request:'SAVE_REVIEW',showWait:true});
}
AUSOUG 2014 Perth Conference
Code can be scary when you simplify it

Comments

  1. Jeff,

    You’ll get this error if a page item which is set via javascript (such as P2_EMPNO in Helen’s example) is set to hidden and protected. You can either change it to hidden but not protected, or make sure that its value is saved from DOM session state to APEX session state prior to the submit.

    • Sorry if my article wasn’t clear enough David – that is not the problem, and I’m not going to remove the item state protection. To be clear: the session state protection violation is (or at least, was) a *symptom*, and not something that needs to be fixed here.

  2. Check out my old post, maybe it helps:
    http://apexbyg.blogspot.com/2012/11/crazy-little-thing-called-dialog.html

    Br,
    Marko

    • Well, I did delete and recreate the region, and placed it at the end of the page – so maybe that’s what’s solved the problem for me.

      It’s just strange that the timeout trick also worked. Or maybe that the close action on the dialog causes the HTML to be rearranged but not quick enough for the submit; so adding a short delay is enough to have the HTML back in the right order when the page is submitted?

    • Yes Marko! I think it’s your blog post I was remembering. 🙂

  3. I seem to recall that there was an issue when the HTML of the page gets shuffled around and the items on the the dialog region get re-ordered in a different order to what APEX did during render. Then at the time of submit it gets misinterpreted by APEX because the items are not where APEX placed them.
    I suspect that the jQuery Dialog is not aware of the extra hidden items with a p_arg_names name that goes with a protected item.
    Maybe this gets you in the right track. Definitely an annoying problem.

Leave a Reply

Your email address will not be published / Required fields are marked *