Just like in our previous posts where we were concerned about people hitting the browser’s refresh/reload button and overwriting their data with nothingness, we also need to be concerned about people navigating our application via the browser’s back button rather than the in-app menus we’ve provided them. (but hey, we can’t blame them, it’s a bad habit I have too–hitting that back page button!)
So, what’s the problem? Well, a posted instance data is updated as long as we navigate from within our site, doing xf:load from one page to another and updating and saving our instance as we go along. However, if we update an Xforms via the post method that redirects us to another page and then we hit the browser’s back page to return to that page, we lose our updated data. If the user’s not aware of this, they may re-submit and lose their changes. This is not what we won’t.
Let’s take an example from my app. I have a CSS styling page that allows users to update the look of their site or page. The initial styling page has all the options and color choices. After making the choices, the user needs to submit the choices and see an example of the changes he/she made, so they must navigate away from the initial styling page to the example page. Now, in the “see your example” page, there’s a navigation button that saves the instance and loads back to the styling page. The problem comes when someone inadvertently hits the browser back page button instead of the in-app navigation provided.
The solution is quite simple and I can’t believe it took me nearly two days of wading through this and experimenting with that to figure this out.
Here’s what we need to do. There is usually a beginning or main menu we begin with as we navigate our site/application. The key is to have that menu always xf:submit data, rather than xf:load when linking to pages for which data integrity concerns us. Of course, menus don’t usually submit data, so what we do is create a small one item xml instance like this:
<?xml version=”1.0″?>
<data>
<backstop>1</backstop>
</data>
You can put it in the head of your xhtml model or your can make a file and reference an external instance–say “backstop.xml”. I prefer to make a file and reference so that I’ll have it available for other pages if needed.
Now what we do, is instead of xf:load to our pages we actually do a submit–which means you’ll have to set up an xf:submission in the model for each link (action=”linkToFile.php”) as well as an xf:submit in the body–you’ll definitely want to set your xf:submit appearance to “minimal” if you have a lot of links. Of course, if we have informational pages or pages that don’t require data manipulation followed by navigation back and forth to it, then we can just do an xf:load if we like.
Now, the next thing we need to do is take our xhtml pages for which data integrity concerns us and instead of keeping them as *.xhtml files, we’ll wrap them up in PHP code and serve them as application/xhtml +xml with the .php extension. (I’ll post the code later). And we’ll do just like we did in my previous posts concerning PHP overwrite–we’ll have the PHP code check and see if the HTTP_RAW_POST_DATA is empty or not. If it is, then we know someone has reloaded or back-paged from the browser rather than using the in-app menus/routers we’ve provided. If HTTP_etc is empty, we’ll give the user a message and then redirect them back to the main menu.
Now this procedure applies not only to the menu, but to any forms that navigate from one to another–they should “link” via xf:submit rather than xf:load. If a form has it’s own instance, you won’t have to use the “backstop” instance–because all we need is any kind of data being sent. In some cases we’ll actually retrieve and use that data, but in others, such as from the menu, we won’t do a thing with that data because it’s meaningless, it is only being sent as an indicator that we got a call from within our in-app navigation system from one page to another.
Here’s some sample code. First the main menu xthml file.
<?xml version="1.0"?>
<?xml-stylesheet href="Forms/zstyle.css" type="text/css"?>
<?xml-stylesheet href="Forms/zstylexf.css" type="text/css"?>
<?xml-stylesheet href="Forms/zstylecr.css" type="text/css"?>
<h:html xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:cr="http://www.cr.com/2007/markup"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<h:head>
<h:title>
Main Menu
</h:title>
<xf:model>
<xf:instance src="backstop.xml"/>
<xf:submission id="optionsMenu" action="optionsMenu.php" method="post"/>
<xf:submission id="fileManager" action="fileManager.php" method="post"/>
<xf:submission id="styling" action="stylepageMaker.php" method="post"/>
<xf:submission id="stats" action="stats.php" method="post"/>
<xf:submission id="clients" action="clients.php" method="post"/>
</xf:model>
</h:head>
<h:body>
<h:div class='divx'>
<cr:ii>
<h:strong> Main Menu </h:strong>
<h:fieldset style="background-color:#cccc99; position:relative; left:2ex; top:2ex;
width:21ex; padding:3ex; border-width:1px; border-color:#000033; font-size:85%">
<xf:submit id="optionsMenu" class="ztagsbox" submission="optionsMenu" appearance="minimal">
<xf:label class="ssubmit">
<h:fieldset class="barmenu">
Make a new form
</h:fieldset>
</xf:label>
</xf:submit>
<h:br/>
<xf:submit id="fileManager" class="ztagsbox" submission="fileManager" appearance="minimal">
<xf:label class="ssubmit">
<h:fieldset class="barmenu">
View or Delete forms
</h:fieldset>
</xf:label>
</xf:submit>
<h:br/>
<xf:submit id="styling" class="ztagsbox" submission="styling" appearance="minimal">
<xf:label class="ssubmit">
<h:fieldset class="barmenu">
Style forms
</h:fieldset>
</xf:label>
</xf:submit>
<h:br/>
<xf:submit id="stats" class="ztagsbox" submission="stats" appearance="minimal">
<xf:label class="ssubmit">
<h:fieldset class="barmenu">
Work with Data
</h:fieldset>
</xf:label>
</xf:submit>
<h:br/>
<xf:submit id="clients" class="ztagsbox" submission="clients" appearance="minimal">
<xf:label class="ssubmit">
<h:fieldset class="barmenu">
Clients
</h:fieldset>
</xf:label>
</xf:submit>
</h:fieldset>
</cr:ii>
</h:div>
<h:p/>
</h:body>
</h:html>
Now for an xhtml as PHP excerpt (the *.php file):
<?php
header("Content-type: application/xhtml+xml");
if (!isset($HTTP_RAW_POST_DATA))
$HTTP_RAW_POST_DATA = file_get_contents("php://input");
//setup "Redirect" message
$redirect= <<<PG
<?xml version="1.0"?>
<?xml-stylesheet href="saveOnlineTest.css" type="text/css"?>
<h:html
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:cr="http://www.cr.com/2007/markup">
<h:head>
<h:title>
Redirect
</h:title>
</h:head>
<h:body>
<h:fieldset style="text-align:left; margin-left:10ex; color:darkslategray">
You have reached this page using the Firefox navigation
toolbar or menu. <h:p><h:em>This is not a problem</h:em>.</h:p>
However, in order to ensure data integrity, you'll need to
redirect to the Main Menu. <h:p/> To avoid this page in the future,
please navigate using the application menu or router
rather than the Firefox toolbar or menu. <h:p/>
<xf:trigger>
<xf:label>
<h:span style="color:brown;">Return to Main Menu</h:span>
</xf:label>
<xf:load resource="mainMenu.xhtml" show="replace" ev:event="DOMActivate"/>
</xf:trigger>
</h:fieldset>
</h:body>
</h:html>
PG;
if ( empty($HTTP_RAW_POST_DATA) )
{ echo $redirect; exit; }
$fileContents=file_get_contents("optionsMenuInstance.xml");
save2file("optionsMenuInstance.xml",$fileContents);
//below is the actual form read in as a variable string for later output (echo)
$page= <<<PG
<?xml version="1.0" ?>
<?xml-stylesheet href="optionsMenu.css" type="text/css"?>
<h:html xmlns:h="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:cr="http://www.cr.com/2007/markup" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<h:head>
<h:title>
Ztags for Xforms
</h:title>
<xf:model id="mod1">
<xf:instance src="optionsMenuInstance.xml"/>
. . .
</h:head>
<h:body>
. . .
</h:body>
</h:html>
PG;
echo $page;
?>

[...] Xforms for Redirecting/Reloading+= pages In an earlier post– don’t hit the back arrow! — I was using Xforms to prevent loss of recent data from a browsers back button or browser [...]
Pingback by Using Xforms for Redirecting/Reloading pages « Clarkepeters’s Weblog — September 11, 2007 @ 8:23 pm
[...] Part 4. don’t hit the back arrow! [...]
Pingback by ClarkePeter’s Weblog » Navigating your site with Xforms and PHP — October 21, 2008 @ 10:06 am