Browser History Management for ColdFusion 8 Ajax using the Yahoo Interface Library (YUI)

One of the things about loading pages using Ajax (not refreshing the page) is that the browser back/forward buttons stop working. Since you are not refreshing the page the browser doesn't record to its history engine.

ColdFusion 8 does not implement automatic browser history management for ColdFusion.navigate and AjaxLink (do it with 9 Adobe). That meant either build your own solution, or in this case I decided to use the YUI Browser History Manager. So lets see how it was done.

Demo the the implementation Here.

The main thing to notice is that a hash value is added to the URL as you click the links (#section=away and #section=home). Lets now look at the YUI Library and how this was implemented.

First, we neeed the YUI Libraries that will implement this functionality. You can include them directory from the Yahoo server.
   view plainprintabout
 <!--- The YUI libraries needed to execute the History Management --->
 <script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/yahoo-dom-event/yahoo-dom-event.js"></script>
 <script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/connection/connection-min.js"></script>
 <script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/history/history-min.js"></script>
We need to put in an iframe, needed epsecially to support Internet Explorer. This also must be put immediately after your opening tag. Also used some CSS to hide the iframe.
   view plainprintabout
 <style>
 #yui-history-iframe {
      position:absolute;
      top:0; left:0;
      width:1px; height:1px;
      visibility:hidden;
     }
 </style>
 <!--- Needed for IE --->
10  <iframe id="yui-history-iframe" src="blank.html"></iframe>
11  <input id="yui-history-field" type="hidden">
The first important step is module registration. This is accompanied by,
   view plainprintabout
 YAHOO.util.History.register("section", initSection, loadSection);
  • section is your module name. This is also the variable used for the hash value in the URL (thats why on the demo we saw #section=away).
  • initsection
  • is a variable that stores your default state of the application. So in the case of the demo we had it set to 'home'.
  • loadSection is a javascript function that will be called anything the user uses the forward/back buttons or when we make a call YAHOO.util.History.navigate function. This is where we will use ColdFusion.navigate to direct the user.
New history entries are stored into the browser stack by calling the YAHOO.util.History.navigate function. The first parameter to the function is the module we registered and the section parameter is the new state of the module.
   view plainprintabout
 YAHOO.util.History.navigate("section", newsection);
We also need to load the default/initial section when the page loads (first visit of a user). This is done using the Library's onReady method.
   view plainprintabout
 YAHOO.util.History.onReady(function () {     
  loadSection(initSection);
  });
We also need to initialize the YUI Browser History Manager. This is done simply by calling the initialize function which takes in the ids of the HTML elements we created at the top of the page.
   view plainprintabout
 YAHOO.util.History.initialize("yui-history-field", "yui-history-iframe");
The final code for my demo was:
   view plainprintabout
 <html>
 <head>
     <!--- The YUI libraries needed to execute the History Management --->
     <script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/yahoo-dom-event/yahoo-dom-event.js"></script>
     <script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/connection/connection-min.js"></script>
     <script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/history/history-min.js"></script>
     <!--- Hide the iframe --->
     <style>
         #yui-history-iframe {
10               position:absolute;
11               top:0; left:0;
12               width:1px; height:1px;
13               visibility:hidden;
14              }
15      </style>
16  </head>
17  
18  <body>
19      <!--- Needed for IE --->
20      <iframe id="yui-history-iframe" src="blank.html"></iframe>
21   <input id="yui-history-field" type="hidden">
22  
23  <div id="nav">
24      <ul>
25          <li><a href="javascript:doNav('home');">Home</a></li>
26          <li><a href="javascript:doNav('away');">Away</a></li>
27      </ul>
28  </div>
29  
30  <cfajaximport tags="cfform">
31  
32  <!--- This is where all the content will be loaded --->
33  <cfdiv id="content">
34  
35  </cfdiv>
36  
37  <script>
38      function doNav(newsection)
39      {
40          //We only register the brower history entry. Storing this automatically calls the loadSection function defined below.
41          YAHOO.util.History.navigate("section", newsection);
42              
43      }
44      
45   //This function takes in the section variable and redirects the content cfdiv to the proper place.
46   //You could shorten and combine the doNav and loadSection functions if needed.
47   //We call this function through the
48   function loadSection(section) {
49  
50          switch(section)
51          {
52              case 'home':
53              ColdFusion.navigate('test.cfm','content');
54              break;
55              case 'away':
56              ColdFusion.navigate('test1.cfm','content');
57              break;
58          }
59  
60  
61   };
62  
63   //This is the default section that needs to be loaded, in other words your home page.
64   initSection = "home";
65  
66   // Register our only module. Module registration MUST take place
67   // BEFORE calling initializing the browser history management library!
68   //YAHOO.util.History.register("section", initSection, function (state) {
69   // This is called after calling YAHOO.util.History.navigate,
70   // or after the user has trigerred the back/forward button.
71   // We cannot distinguish between these two situations.
72   //loadSection(state);
73   //});
74  
75   //We must register our navigation module, which I have called section with Yahoo's history manager
76   // This has to be done before initializing the history manager
77   YAHOO.util.History.register("section", initSection, loadSection);
78   //loadSection function is called after calling YAHOO.util.History.navigate,
79   // or after the user has trigerred the back/forward button.
80   // We cannot distinguish between these two situations.
81  
82   // Use the Browser History Manager onReady method to initialize the application.
83   YAHOO.util.History.onReady(function () {     
84   //We load the default state into the cfdiv
85   loadSection(initSection);
86   });
87  
88   // Initialize the browser history management library.
89   try {
90   YAHOO.util.History.initialize("yui-history-field", "yui-history-iframe");
91   } catch (e) {
92   // The only exception that gets thrown here is when the browser is
93   // not supported (Opera, or not A-grade) Degrade gracefully.
94   // This is used for normal navigation in case our history manager initialization failed
95   loadSection(initSection);
96   }
97  
98   </script>
99  
100   </body>
101  </html>
So, when the user clicks the Away link the following happens:
  1. The doNav() function takes the new state (away) and passes it to Yahoo.util.History.navigate to store what will be the next state of the application.
  2. Since we register the new state, the loadSection function is automatically called. This function also takes in the section parameter and based on it uses ColdFusion.navigate to direct the content cfdiv.
Similarly when the Forward/Back buttons are clicked, we take care of navigation based on the state change. It is important to note that this Browser History Management does not work on Opera. Note: This was also posted at Ray Camden's Blog. I would like to thank him for that. Ray also added a small piece of code that will enable bookmarking for your application:
   view plainprintabout
 if(document.location.hash != '') {
  if(document.location.hash.indexOf('#section=') == 0) {
  initSection = document.location.hash.substr(9, document.location.hash.length);
  }
 }
If you have ideas to improve the implementation, feel free to participate there or here, or contact me.

Related Blog Entries

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
BlogCFC was created by Raymond Camden. This blog is running version 5.9.5.003.  Design based on ARCLITE by: digitalnature