The jQuery Mobile framework does not track dialogs in history. A dialog will thus not reappear when you click on the back button of your browser. Using a dialog for some features, for example to show an error pop up or an alert, has a minor issue that is very visible. When the dialog is opened from a page, the address bar will show the page URL suffixed with the #&ui-state=dialog
text. This might not be desirable to all. This recipe shows you how to use the History API and customize a regular dialog to appear, such as a pop up without any changes to the URL, making use of the History API.
Copy the full code of this recipe from the code/02/history
sources folder. You can launch this code using the URL http://localhost:8080/02/history/main.html
.
The steps to be followed are:
Create main.html
, and add a link to open the errordialog.html
file as a dialog. Also add an input
button, as shown in the following code snippet:
<div id="main" data-role="page"> <div data-role="header"> <h1>Header of Main</h1> </div> <div data-role="content"> <a href="errordialog.html" data-theme="b" data-role="button" data-rel="dialog"> Dialog </a> <input type="submit" value="Popup" id="linkButton" data-theme="b"/> </div> <div data-role="footer"> <h4>Footer of Main</h4> </div> </div>
Add the following script to the <head>
section of main.html
to open errorpopup.html
as a dialog on the click
event of the input
button:
$("#main").live("pageinit", function(event) { $("#linkButton").bind( "click", function(event, ui) { $.mobile.changePage( "errorpopup.html", { changeHash: false, role: "dialog" }); }); });
Create the errordialog.html
file to show a custom error message. Also add a button to go back to main.html
, as shown in the following code snippet:
<div id="errordialog" data-role="page"> <div data-role="header"> <h1>Error !</h1> </div> <div data-role="content"> <p>Please correct and resubmit<p> <a href="main.html" data-role="button" data-theme="b">Close</a> </div> </div>
Create errorpopup.html
, and add the following script inside the page container. This is a regular dialog but it has a custom styled header. Remove its entry from the history stack when you click on the anchor link:
<div id="errorpopup" data-role="page">
<script>
$("#errorpopup").live("pageinit", function(event) {
$("a").click(function(event) {
history.back();
});
});
</script>
Then, add a custom header to the page and also add the link to go back to main.html
:
<div class="ui-corner-top ui-overlay-shadow ui-header ui-bar-a" role="banner"> <h1 class="ui-title" tabindex="0" role="heading" aria-level="1"> Error ! </h1> </div> <div data-role="content"> <p>Please correct and resubmit<p> <a href="main.html" data-role="button" data- theme="b"> Close </a> </div> </div>
Create main.html
with the #main
page having a link to open the errordialog.html
page. Add an input submit button (id="linkButton"
) as shown. Next, create the errordialog.html
page with a button to go back to main.html
as given in the code. When you launch the app and click on the first button (Dialog), the errordialog.html
page is opened as a regular dialog with the pop transition. You will see the address bar change and show the #&ui-state=dialog
text at the end of the URL, as shown in the following screenshot. Close and open this dialog a couple of times, and then if you press and hold the back button, the browser's history is displayed and you will see entries for the Error Dialog made in the history stack list:
Now, in main.html
, add the given script to the pageinit
event handler that gets invoked when the app starts. Here, handle the click
event of the #linkButton
input button, and invoke the changePage()
method in the callback with the options described in the following section, to open the errorpopup.html
page. Set the role
option as dialog
to open the page as a dialog. Also, set the changeHash
option to false
, to indicate that the URL hash must not be changed in the address bar when the page is opened.
Next, create errorpopup.html
and add the given script inside the page container. In this script, bind the pageinit
event that gets invoked when the page is initialized. Here, add an event handler for the click
event of the anchor button. In this callback, invoke the history.back()
method to remove the history entry made on the history stack. You should add this script in the page container, so that it gets invoked every time the page gets loaded and initialized in the DOM.
Next, add a custom header to the error pop-up page container. This custom header is the same as the one used in the Custom styling a dialog recipe, earlier in this chapter. This dialog header is customized to make it look more like a pop up and to avoid the close button, which is present by default in the dialog header. Finally, in the page content, add a button to go back to main.html
.
Now, launch the app again and click on the second button (Popup). The custom dialog created is shown as a pop up, as shown in the following screenshot:
This pop up behaves differently from the default dialog. The Close icon is not present. You will note that the browser's address bar is not changed. You will also see that the Error Popup page title is not shown in the history list when you click and hold the browser's back button. Close the pop up and go back to main.html
. You can click and hold the browser's back or front button to see that the pop up is never shown in the history list, whereas the dialog is listed, as shown in the following screenshot:
The History API is very easy to use, and provides additional methods with which you can handle and manipulate the history stack in the browser. You can use the pushState()
method to add a new entry into the history. With replaceState()
, you can replace the history entry and the URL of an existing entry in the stack. This is a very handy method and lets you manipulate the history to suit your app's needs. As shown in the code listed in this recipe, history.back()
takes you back one step in the history, whereas history.forward()
takes you one step forward. To go to a specific entry in the history stack, you can also use the history.go()
method, passing it a numerical value on how many entries you want to jump. So, history.go(-3)
will take you three entries back, and a plus value will take you three entries forward.
Whenever you click on the back or forward buttons, a popstate
event is thrown. This event is handled by the framework using the onpopstate
handler, and the framework navigates to the next or previous page as desired. If popstate
results in the target page being a dialog, the framework handles the event and does not navigate back to the dialog. Thus the dialog is not shown again when you click on the forward or back buttons in your browser.
At the time of writing this recipe, jQuery Mobile v1.1.1 was used. So the error pop-up dialog created in this recipe is not a true pop up, as it still displayed in a separate page and does not hover over the original page. The Popup widget will be available with jQuery Mobile v1.2.0. Then you can add a simple, true pop up using the data-rel="popup"
attribute, as shown in the following code snippet:
<a href="#myPopup" data-rel="popup">Open Popup</a> <div data-role="popup" id="myPopup"> <p>A simple true popup!<p> </div>
You can optionally set the pop up not to be tracked in history using the data-history="false"
attribute. You can read more about using pop ups at http://jquerymobile.com/demos/1.2.0/docs/pages/popup/index.html.