Implementing Cross-Browser Compatible Smart Navigation Features
by Damon Armstrong
Rating:
Smart
Navigation is a feature built into ASP.NET that makes postbacks
smoother by remembering the page scroll position, retaining element
focus, reducing screen flicker, and not registering the postback in the
browser?s history. This greatly enhances the user experience for pages
that make use of postbacks, but it only works in Internet Explorer 5.5
and up. In this article Damon Armstrong will discuss how to build
similar page position and focus tracking features, but which will work
in all modern, standards compliant browsers.
Introduction
On a recent project for a government client I was tasked with creating a user
information page that needed to identify the region and office in which an
individual worked. There were around 3,000 total offices, so I ended up
creating two drop down lists to help narrow down the selection. The first drop
down contained a list of all of the regions, and the second was automatically
populated with region-specific offices by autopostbacking the form when a
region was selected. Because the form had a number of data entry fields, these
drop down lists were located near the bottom of the form and required viewers
to scroll down to see them. It worked well in Internet Explorer. The trouble
was, it only worked in Internet Explorer and some of our users had other
browsers.
Inevitably, slightly irritated people began calling in and complaining that when
they selected a region they were returned to the top of the page after the
postback. This meant they had to scroll all the way back down the page to
select an item from the office drop down list, and it was a bit irksome. They
wanted the page to stay in the same place and maintain the tab position so they
could just tab over to the office drop down. They wanted the Smart Navigation
features that would have been available had they been using Internet Explorer.
My first inclination was to tell them download Internet Explorer because it
would make all of their problems go away without much effort on my part, but I
had a feeling that wouldnt go down very well. People who used browsers other
than Internet Explorer are comfortable with and partial to their browsers, so
why should they have to change? Instead, I decided it would be better to build
something that would mimic the ASP.NET Smart Navigation functionality but which
would be compatible with the most recent versions of Navigator, Opera, and
FireFox.
This article is going to cover how to go about implementing some of the Smart
Navigation functionality found in ASP.NET using cross-browser compatible
JavaScript. It will also wrap all of the code into an easy to reuse assembly so
you can import it into whatever projects you so choose without having to do a
lot of reworking.
To understand this article you should have a good understanding of JavaScript,
as well as the page scripting model. If you have never heard of the
Page.RegisterClientScriptBlock()
method then you should check out the links section of this article and do some
catching up before pressing onward.
I'll be discussing, in some detail, how all the code works. But I know there are
those of you out there who wont really want to get into it that deep into the
underlying mechanism, but would just prefer to use the code. I sympathize with
you, so if you are one of these people then you should read the "Using
SmartNav on a Page" section. For those of you that want a more in depth
understanding, I'll be discussing what Smart Navigation is, how it works, and
getting into the details of how to implement our own version of the features
with cross-browser compatible code.
System Requirements
To run the code for this sample you should have
A web server running on Windows 2000 or later
The .NET Framework version 1.1
VS.NET 2003
Installing and Compiling the Sample Code
Full instructions for installing the sample code are contained in the ReadMe.txt
file that comes with the download. To make the sample easier to install, I've
provided an installer file,
SmartNavSetup.msi
This will launch a setup program that will create the appropriate IIS entries
and a
SmartNavDemo
virtual directory and copy the sample application there. There is one step that
the installation routine doesn't do, which you must therefore do by hand: You
will need to copy the
WebTools.js
file from
[webroot]/ SmartNavDemo/WebTools/ClientScript
to
[webroot]/aspnet_client/WebTools
. The
aspnet_client
directory is a central location where web applications for your site can find
client-side script files, and the code in the sample application expects the
file to be in this location. The sample won't work correctly if you don't carry
out this step . There is a batch file called
deploy.bat
that can automatically create the necessary directory structure and copy the
WebTools.js
file into the appropriate location if your webroot is located in
c:\inetpub\wwwroot
.
I have also included a copy of the demo application for XCOPY deployment if you
have any issues with the setup file.
Running the Sample Application
If you run the sample application's Default.aspx page, you'll see a menu with
various links to other pages, as shown in figure 1. This page gives a pretty
good explanation of the purposes of the other pages so I'll let Figure 1 speak
for itself:
Figure 1. The sample application, on startup.
Other than the Browser information page, any of the links will get to to an
identical-looking form. The contents of this form are not important it simply
contains a sufficiently large number of controls that you may have to scroll
down to see them all, as shown in figure Figure 2.
Figure 2. The large form in the sample application.
Some of the controls have auto-postback enabled, and there's a submit button to
submit the entire form. No action is taken when you submit the form; the
interest in this article is that, with the smart navigation that I will code
up, the form will be able to remember its scroll position and which control has
the focus when you post back, in any modern browser.
What is Smart Navigation?
Smart Navigation is a feature of ASP.NET that makes post backs from web forms a
bit more user friendly. It accomplishes a couple of key tasks such as
maintaining scroll position, element focus, reducing screen flicker, and not
registering the redisplayed page in the browsers history. The functionality,
however, is highly dependent on Internet Explorer specific features and it does
not work across all browsers. You can take a look at the Smart Navigation code
by opening the
SmartNav.js
client-side script file located in the
/aspnet_client/system_web/[version]/
folder, but be warned that it is a very advanced piece of code. Don't edit it.
Whenever a page has Smart Navigation enabled, the page will be output with a
hidden iFrame and a reference to the SmartNav.js file. The client-script then
registers functions that allow the iFrame to respond to events that occur on
the web form, such as when the page loads or is submitted.
The general idea behind Smart Navigation is that the hidden iFrame is
responsible for a lot of the page processing. When the user submits the web
form, the iFrame gathers all the form data and sends it to the server for
processing. It also determines which element currently has the focus, and saves
this information for later use. The HTML response from the server is then
received by the iFrame, which then writes that HTML out to the actual web form
once it has been completely received.
This accomplishes two things. First, it reduces flicker. Normally, a page is
cleared completely before new content is displayed, causing a completely white
page to be shown briefly before the new content is presented. If the content of
the submitted page and the new page is similar, the page just appears to
flicker. When the iFrame writes HTML back to the web form, however, the output
is displayed without clearing all the contents of the page. There is no
momentary flash of white, so flicker is therefore reduced. Second, it maintains
scroll position. Since the web form never actually submits, the page position
never gets reset. When the iFrame rewrites the web form using the HTML response
from the server, the web form will still be in its original location because it
never moved.
Client-script from the SmartNav.js file is also responsible for resetting the
element focus after loading the HTML into the web form, and for ensuring that
history is not saved for post backs. By avoiding an entry into the browser
history during post backs, Smart Navigation helps avoid issues with users
clicking the back button and being presented with a dialog box asking them if
they want to resubmit their form data. Considering that there could be many
postbacks from a single page, this is a very useful feature.
Nothing is perfect, however, and Smart Navigation is no exception. There will be
times when using Smart Navigation wont work or causes bugs to pop up. And, as
mentioned before, it doesnt work in all browsers, which tends to exclude its
use on major public websites. But its a great option for an intranet
application where all of your users are on Internet Explorer.
In our implementation of cross-browser compatible Smart Navigation features we
are going to focus on retaining page position and element focus. Page flicker
is a minor annoyance that is rapidly decreasing with processor speed, and the
history issue can be lessened with appropriate navigation options. If you give
people obvious navigation routes then they may be less inclined to use the back
button, although because many people are so accustomed to the ease of the back
button, you're unlikely to completely prevent users from using it. Hence you
should still take care to ensure that your code can cope with an accidental
resubmission and behaves sensibly if that happens.
SmartNavigation Implementation Overview
In this section I'll go over what the implementation of the sample code looks
like, so you can see how the various projects and files fit in.
Solution Architecture
The demo application itself is fairly straightforward. There are two projects in
the VS. NET solution: The web application, and the assembly that contains the
smart navigation features.
The web application contains the following pages:
Default.aspxOrganizational page displaying
links and descriptions of other pages.
NoSmartNav.aspx
Webform with Microsofts Smart Navigation disabled.
SmartNavIE.aspx
Webform with Microsofts Smart Navigation enabled.
SmartNavJavaScript.aspx
Webform using our implementation of the cross-browser
compatible Smart Navigation features.
BrowserInfo.aspx
Shows browser information using the Request.Browser
object, and the window.navigator.appName property in JavaScript.
You can open these pages up in various browsers to see the different behaviors
in each. You should notice when Smart Navigation is enabled that Internet
Explorer will stay in the same position when a postback occurs. In other
browsers, the page will return to the top left. You should also notice that the
Request.Browser object correctly identifies the browser types, but that Opera
and FireFox identify themselves as Internet Explorer and Netscape
(respectively) from the window.navigator.appName property in JavaScript.
The
WebTools
project wraps the JavaScript Smart Navigation features into an easily reusable
assembly. There are two classes
Scripting.vbContains methods for DoPostBack
Hijacking
SmartNav.vb
Contains methods for JavaScript smart navigation
This assembly assembly contains the.NET code that allows you to enable page
position and focus tracking from a web form. It is encapsulated in an assembly
for easy reuse across multiple projects.
The
WebTools
assembly also contains the client-side script file named
WebTools.js
that should be deployed to the
/aspnet_client/WebTools folder
, as mentioned earlier. It contains static methods to assist with the page
position and focus tracking features, and it is included on each page in which
you want to use the functionality we will be implementing. Note that any
changes you make to the WebTools.js file included in the project will not take
effect until those changes are copied to the
/aspnet_client/WebTools
folder.
Figure 3 shows the overall file structure of the applciation.
p>Figure 3. Overview and File Structure of the Sample Appliation
Pages in your ASP.NET application make use of the WebTools assembly by calling
the
WebTools.SmartNav.Enable()
method. Calling this method will output the necessary JavaScript on the page
sent to the browser so the page position and focus information will be tracked.
It also make sure the right JavaScript include information is sent to the
browser so the browser will reference the
WebTools.js
script file.
I'll now quickly review the individual parts of the application in more detail.
WebTools.js
The bulk of the JavaScript used for the smart navigation is encapsulated in the
WebTools.js
client-side script file. Placing this code in a client-side script file allows
browsers to cache the document, thus saving bandwidth in the long run.
Additionally, the
WebTools.js
file is located in a directory from which all of your web applications can
access it. This allows multiple applications for a site to reference the same
client-side script file and provides a single location that you need to update
if changes are required to the script.
You will see code in the SmartNav class registering client-side script for page
execution that makes use of the functions located in the
WebTools.js
file.
Scripting.vb
This file contains a workaround for a behavioral issue with the
Page.RegisterOnSubmitStatement()
method. This issue and workaround were documented in a recently published ASP
Today article I wrote, DoPostBack Hijacking so I will not cover it in detail in
this article. If you would like a full understanding of the issue, a link to
this article is provided in the links section, but you can get by with what we
talk about here if you so choose.
The JavaScript methods required to implement DoPostBack Hijacking and the
workaround mentioned above are located at the end of the
WebTools.js
file. You will see code in the Scripting class registering client-side script
for page execution that makes use of those functions.
SmartNav.vb
The SmartNav class contains the code for registering client-side script on a
page that will setup scroll position and tab location tracking. Methods from
this class will be called from a web form (.aspx page) to enable JavaScript
Smart Navigation.
The process works like this:
The page will call the
SmartNav.Enable()
method.
Three hidden form variables will be added to the page.
__lastTab
will hold the last known tab position.
__leftPos
will hold the X (horizontal) scroll position.
__topPos
will hold the Y (vertical) scroll position
SmartNav.Enable()
will register the
WebTools.js
client-side file on the page. This ensures that the SmartNav JavaScript
functions will be available on the client.
SmartNav.Enable()
will register the required JavaScript functions with the page that are used to
populate the three hidden variables when the page closes.
If a postback occurs, the
SmartNav.Enable()
method will read the hidden variables and register JavaScript functions for
execution when the page loads. These functions will return the page to the
proper scroll position and setup the appropriate tab location.
The Web Forms (.aspx Pages)
The Web Forms need to call
SmartNav.Enable()
to setup JavaScript Smart Navigation. JavaScript functions will be registered
on the page through that function, then output the browser when the page
renders.
The browser is where everything comes together and executes. The browser will
pull down the
WebTools.js
client-side script file and execute JavaScript functions on the page to save
page location and tab position before each form submission. The browser will
then send these items back to the web form for processing via the hidden form
variables.
The Client-Side JavaScript
All of the client-side functions needed to implement JavaScript Smart Navigation
are located in the
WebTools.js
client-side script file. As mentioned earlier, this file is located in the
aspnet_client
subdirectory of the webroot in a directory called
WebTools
. The aspnet_client directory is created when ASP.NET is installed to hold
client-side include files that are available to multiple applications. If you
drill down through the directory structure, you will find all of ASP.NETs
validation routines and Internet Explorer specific Smart Navigation files.
Microsoft recommends that you place your non-application specific include files
in this directory because it is a central repository for client-script files
for a site.
There are five main functions that I'll be discussing in the
WebTools.js
client-side script file that deal specifically with JavaScript Smart
Navigation:
setFocus()
,
saveTabPos()
,
setupTrackTab()
,
setScrollPos()
, and
getScrollPos()
. There are three additional functions that pertain to DoPostBack Hijacking.
DoPostBack Hijacking is a technique that replaces the
DoPostBack()
function written to a page by ASP.NET with another function written by a
developer. DoPostBack Hijacking is used to implementing a workaround for the
behavioral issues in the
Page.RegisterOnSubmitStatement()
method. I won't cover those functions because they are outlined in detail in my
earlier article on DoPostBack Hijacking. A link to the article is provided in
the links section.
The setFocus() Function
When the page is loaded, we need to be able to set the focus to a particular
page element. The setFocus function accomplishes this task for us. The code for
the setFocus function is shown below:
function setFocus(elementId){
if(document.getElementById){
//getElementById is supported, so use it
if(document.getElementById(elementId)){
document.getElementById(elementId).focus();
}
}else{
if(document.getElementsByName){
var items = document.getElementsByName(elementId);
if(items.length > 0){
items[0].focus();
}
}
}
}//end function
This function takes a single parameter called
elementId
that defines the HTML element that should receive the focus. Notice that the
first
if
statement is used to determine whether or not the browser supports the
getElementById
function. If so, then we determine whether or not the elementId references a
valid element on the page on the page. If it does, we call the focus function
of that element. At the time of writing, IE, Firefox, and Opera all support the
getElementById()
function. Netscape, however, does not.
If someone is using the Netscape browser then we must use the
document.getElementsByName()
function to locate the item that is to receive the focus. The
document.getElementByName()
function returns an array, so we create a variable to hold all of the return
values. If the length is greater than zero, we assume the first item in the
array is the item for which we are looking and call its
focus()
method to set the focus to the element.
The saveTabPos() Function
We can set the tab position, but we also need to be able to save it when the
page is submitted. The
saveTabPos()
function is used for this. When the
SmartNav.Enable()
method is called, it will save the element id of the active element in a hidden
form variable named
__lastTab
The code for this function is shown below:
function saveTabPos(formName){
if(document.forms[formName]){
if(document.forms[formName].__lastTab){
document.forms[formName].__lastTab.value =
document.activeElement.name;
}//end if
}//end if
return true
}//end function
The
saveTabPos()
function is passed the name of the form that contains the
__lastTab
variable. It checks to ensure a form object can be located with the given
formName
, that the
__lastTab
variable can be located with that form object, and if so it then sets the
__lastTab
variable to the name of
activeElement
in the
document
.
The setupTrackTab() Function
Internet Explorer and Opera let us know what element currently has the focus via
the
document.activeElement
property. Netscape and Firefox do not have a corresponding property to let us
know this information, so we have to setup a mechanism to determine this on our
own.
Heres the plan. If the browser identifies itself as Netscape, which both
Netscape and Firefox do, then we are going to iterate through each one of the
elements looking for items that have a
focus()
method. The objective of us saving the element name is to call the
focus()
method on the element later on when the page refreshes. Thus, if the item does
not have the focus method then we can ignore the element.
If the item does have the
focus()
method, then we need alter its
onfocus
property. Remember that the
onfocus
property is a JavaScript string that will be executed when the item comes into
focus. We want the following JavaScript to execute whenever an item comes into
focus:
document.activeElement = this;
This will effectively set the
document.activeElement
property in Netscape to the item that currently has the focus. The code to
accomplish this task is outlined below.
function setupTrackTab(){
if (window.navigator.appName.toLowerCase().indexOf("netscape") > -1) {
var allElements = document.body.getElementsByTagName('*');
for (var i = 0; i<allElements.length; i++) {
if(allElements[i].focus != undefined){
var functionBody = 'document.activeElement = this;';
var oldOnFocus = allElements[i].getAttribute('onfocus');
if (oldOnFocus) functionBody += oldOnFocus;
allElements[i].onfocus = new Function (
'event', functionBody);
}//end if
}//end for
}//end if
}//end function
The first if statement determines whether the browser identifies itself as
Netscape. Opera will identify itself as Internet Explorer, and Opera supports
the activeElement property. So, for Opera and Internet Explorer we do not have
to do anything in this function. If the browser is Netscape or Firefox, then we
need to setup our own activeElement property so tab tracking will function
appropriately.
Once we are in the main
if
statement, we setup a variable named
allElements
that will contain an array of all the elements on the page. Using a
for
loop, we iterate through all of the elements on the page. The
if
statement inside of the
for
loop determines whether or not the item has a
focus()
method. If the element has a
focus()
method, we will alter its
onfocus
property. If there is not onfocus property, we disregard the item because we
are only interested in elements that can receive the focus.
It is perfectly reasonable to expect the
onfocus
property to already have JavaScript in it, so we have to take that into account
when modifying it. First, we create a variable named
functionBody
that contains the JavaScript we want executed to setup our
activeElement
property. Then, we get the JavaScript that is currently in the element and
place that into a variable named
oldOnFocus
. If any JavaScript is contained in
oldOnFocus
, then we add it to the end of
functionBody
. This allows our code to execute first, and then the code that was there
previously to execute next. Finally, we create a new Function object with the
code contained in
functionBody
and assign it to the
onfocus
property of the element.
Although it was fairly troublesome, this will effectively mimic the
activeElement
property of the
document
object found in Internet Explorer. Now that weve covered all of the functions
required to track the tab position, lets move right into tracking the scroll
position.
The getScrollPos() Function
We need the ability to acquire the scroll position before the page is submitted
for a postback, and this is the method that accomplishes that task. Following
is the code for the
getScrollPos()
function:
function getScrollPos(formName){
if(document.forms[formName]){
if(document.forms[formName].__leftPos){
document.forms[formName].__leftPos.value =
document.body.scrollLeft;
document.forms[formName].__topPos.value = document.body.scrollTop;
}
}
}
This function is passed the name of the form that contains the
__leftPos
and
__rightPos
hidden form variables. The first line of code checks to make sure that the
formName
references a valid form on the page. The next line checks to make sure that the
__leftPos
hidden form variable is defined. If so, we assume that
__topPos
is also defined and we set the values to the
scrollLeft
and
scrollTop
properties of the
document
.
body
object, respectively. All modern standards compliant browsers support the
document.body.scrollLeft
, and
document.body.scrollTop
properties, so we do not have to do any special checking here.
The setScrollPos Function
We also need the ability to set the scroll position of the browser when the page
is loaded. This is accomplished from the
setScrollPos()
function. Following is the code for the function. Like the
getScrollPos()
function, it is relatively simple because FireFox, Opera, Netscape, and
Interenet Explorer all support the same scroll position properties.
function setScrollPos(leftPos,topPos){
try{
document.body.scrollLeft = leftPos;
document.body.scrollTop = topPos;
catch(ex){
lastExceptionLocation = 'setScrollPos';
lastException = ex;
}
}
This function is given two parameters:
leftPos
and
topPos
. The
leftPos
parameter contains the horizontal scroll position and the value of this
parameter is passed into the
document.body.scrollLeft
property. The
topPos
parameter contains the vertical scroll position and its value is passed into
the
document.body.scrollTop
property.
The Server-Side Scripting Class
The Scripting class, defined in Scripting.vb, contains three methods that we
will be using from within the
SmartNav
class. The first method is called
RegisterClientScript()
and it is used to ensure WebTools.js will be included in the page by
registering the following JavaScript:
<script language="javascript" src="/aspnet_client/WebTools/WebTools.js"
</script>
Next, there is a function called
LocateServerForm()
. This function is responsible for returning the name of the server from used
by an ASP.NET page. It iterates through all of the elements on the page until
it locates an
HTMLForm
object and returns its ID property. This function is used to pass in the
appropriate form name to the
saveTabPos()
and
getScrollPosition()
client-side functions in
WebTools.js
,
The last method is called
HijackDoPostBack()
. This method is used to ensure JavaScript registered to execute when the page
submits will do so correctly. There is a similar method named
RegisterOnSubmitStatement()
that belongs to the
Page
object, but this method will not execute the specified JavaScript when the page
submits using a
__doPostBack
call. For our scroll and tab position saving functions to work correctly, the
page needs to execute the specified JavaScript when the page submits using a
__doPostBack()
call. Thus, we will be using the
HijackDoPostBack()
method to ensure our JavaScript code is executed as needed. Note that I've not
used the
onscroll
event because this is not supported in Netscape.
Once again, the Scripting class and associated JavaScript functions for
implementing the
HijackDoPostBack()
method are outlined in detail in my DoPostBack Hijacking article.
The Server-Side SmartNav Class
The SmartNav class is what you will be interacting with directly when you are
coding on a page. It contains three shared functions that will help setup Smart
Navigation on a page.
The SetFocus() Method
SetFocus allows you to set an initial element that should receive the focus as
well track the tab position between postbacks. You will notice that it takes
two parameters. The first parameter is a reference to the Page on which you are
trying to setup tab position tracking.
InitialElement
is a string containing the element id of the element that should have the
initial focus. Following is the complete listing of code for the method:
'***************************************************************
Public Shared Sub SetFocus(ByRef Page As System.Web.UI.Page,
ByVal initialElement As String)
Dim lastTab = Page.Request.Form("__lastTab")
If lastTab = String.Empty Then lastTab = initialElement
Page.RegisterHiddenField("__lastTab", "")
Page.RegisterStartupScript("setupTrackTab", _
"<SCRIPT language=""javascript"">setupTrackTab();</SCRIPT>")
Scripting.RegisterOnSubmitStatement(Page, "saveTabPos", "saveTabPos();")
Page.RegisterStartupScript("setInitTab", _
"<script language=""javascript"">setFocus('" & lastTab & "');</script>")
End Sub
The first line attempts to read the value from the
__lastTab
form variable into a variable called
lastTab
. If the page has not posted back, then
lastTab
will end up blank. Otherwise it will contain the element id set from the
saveTabPos
function defined in the
WebTools.js
file. If
lastTab
ends up blank, the next line will set it to the
initialElement
value. This ensures that the default form element on the page will have the
focus instead of the navigation bar or some other browser element. If you do
not want a default form element to receive the focus, then leave the
initialElement
blank.
Next, the page will register the hidden field named
__lastTab
. This makes sure there is a form variable into which we can save the tab
position from the
saveTabPos
function in
WebTools.js
. Not to mention that we just accessed the
__lastTab
form variable two lines ago.
After that, the page will register a startup script to execute the
setupTrackTab
JavaScript function when the page loads. Remember that the
setupTrackTab
function is defined in the WebTools.js include file and is required to setup
the
document.activeElement
property in Netscape.
Then we use the
Scripting.RegisterOnSubmitStatement()
method to ensure that the
saveTabPos()
method will be executed whenever the page submits. This will save the active
element name in the
__lastTab
form variable so this function read it.
Finally, we register a startup script to set the initial tab focus using the
setFocus()
JavaScript function defined in
WebTools.js
. This will ensure that the last tab position or the initial element will have
the focus when the page finishes loading.
The TrackPos() Method
TrackPos()
is used to setup the page to allow for scroll position tracking. It only takes
a single parameter, a reference to the page on which you want to setup the
scroll position tracking. Lets take a look at the code:
'***************************************************************
Public Shared Sub TrackPos(ByRef page As System.Web.UI.Page)
Dim topPos As Integer = 0
Dim leftPos As Integer = 0
If page.IsPostBack Then
If IsNumeric(page.Request.Form("__leftPos")) Then _
leftPos = CInt(page.Request.Form("__leftPos"))
If IsNumeric(page.Request.Form("__topPos")) Then _
topPos = CInt(page.Request.Form("__topPos"))
End If
page.RegisterHiddenField("__leftPos", leftPos)
page.RegisterHiddenField("__topPos", topPos)
page.RegisterStartupScript("TrackXY",
"<script language=""javascript"">setScrollPos(" & _
leftPos & "," & topPos & ");</script>")
Scripting.RegisterOnSubmitStatement(page, _
"getScrollPos", "getScrollPos();")
End Sub
First, we define two variables,
topPos
and
leftPos
, to hold the top and left position information. If this is a postback, then we
attempt to acquire the
__leftPos
and
__topPos
form variables. If they are acquired successfully they are assigned to the
topPos
and
leftPos
variables in our function.
Next, the
TrackPos()
method will ensure that the hidden form variables
__leftPos
and
__topPos
are created on the page. This ensures that the
getScrollPos()
JavaScript function defined in
WebTools.js
has a location to which it can save the scroll position information.
Then we register a startup script that will call the
setScrollPos()
JavaScript function when the page loads. This will make the page return to the
proper location if it is a postback.
Finally, we use the
Scripting.RegisterOnSubmitStatement()
method to ensure
getScrollPos()
will execute when the page is submitted. This ensures that the screen position
information will be saved to the
__leftPos
and
__topPos
form variables for processing inside of this function.
The Enable() Method
Most of the time you will want both tab and scroll position tracking to be
enabled. The Enable method calls both of the functions for you from a single
location. It mainly exists to help reduce typing. There are two overloaded
enable methods:
'***************************************************************
Public Shared Sub Enable(ByRef page As System.Web.UI.Page,
ByVal initialElement As String)
SetFocus(page, initialElement)
TrackPos(page)
End Sub
'***************************************************************
Public Shared Sub Enable(ByRef page As System.Web.UI.Page)
Enable(page, String.Empty)
End Sub
If you want to specify an initial element that should receive the focus, you may
call the first
Enable
method and pass in a string containing the
elementId
of the item that should receive the focus. If you do not want to specify an
initial element, the second
Enable()
method will automatically pass in an empty string as the
initialElement
.
Using SmartNav on a Page
Now that we have covered all the code, we can look at how you should use the
SmartNav class on a page. Before you begin coding, you must have a reference to
the
WebTools
assembly from your web application. You should also reference the WebTools
namespace on your page with the usual
Imports
statement in VB, or
using
statement in C#:
Imports WebTools
You can also setup the WebTools assembly as a global import on the Imports
property page of your web application properties. This can be found by right
clicking on your ASP.NET project and selecting Properties.
With that out of the way, lets take a look at the code from the
SmartNavJavascript.aspx page located in the demo application. The following
line of code is located in the page_load event:
SmartNav.Enable(Me, Me.txtNameFirst.UniqueID)
The first parameter of the Enable method is the page on which you want to enable
JavaScript Smart Navigation. You can just pass in the
Me
reference because you are currently working from within the context of a page.
The second parameter is the element id of the initial page element that should
receive the focus when the page loads. In the example above, I used the
UniqueID
property of the
txtNameFirst
textbox control to get the element ID. You could also type it in as a string if
you so desired, or use the overloaded
Enable()
method to avoid passing in an initial element all together.
And thats it. A single line of code inside the Page_Load event of your web form
can enable JavaScript Smart Navigation for your users cross-browser compatible
enhanced surfing experience. I would caution you against enabling both
ASP.NETs Smart Navigation features and these smart navigation features at the
same time. In brief testing, when both sets of functionality were enabled, the
horizontal scroll position was always reset. Vertical positioning and focus
were retained correctly, however. There may, however, be other issues that
arise when both sets of functionality are enabled that have not yet been
discovered.
One thing you could do, if you want to dynamically switch between ASP.NETs
Smart Navigation and our alternative, is to use the Request.Browser object to
determine whether or not a user has Internet Explorer 5.5 or greater. The code
would look something like this:
With Request.Browser
If .Browser = "IE" AndAlso _
((.MajorVersion > 5) Or _
(.MajorVersion = 5 And .MinorVersion >= 5)) Then
Page.SmartNavigation = True
Else
Page.SmartNavigation = False
WebTools.SmartNav.Enable(Me)
End If
End With
Naturally, you would not want to paste this into each page you create on a
website, so you would most likely want to create an inheritable page class and
have this code in the
load
event of that class. Then have all the pages in your site inherit from that
base page object to include the functionality. Its up to you though.
Conclusion
The Smart Navigation feature of Internet Explorer makes navigating web forms
much more user friendly, and now you can port that power into other browsers as
well. Be wary, however, to stay on your toes. As browsers are updated and newer
versions of the .NET framework are published, this code may need to change
slightly to keep up with the times.