Using History API to create a custom error pop up

Using History API to create a custom error pop up


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.

Getting ready

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.

How to do it...

The steps to be followed are:

  1. 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>
  2. 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"
          });
        });
      });
  3. 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>
  4. 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>
  5. 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>

How it works...

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:

There's more...

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.

The popstate event on a dialog

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.

The Popup widget

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.

See also

  • The Custom styling a dialog recipe

  • The Using page initialization events recipe in Chapter 8, Events

  • The Using changePage() to change a page recipe Chapter 9, Methods and Utilities