Click here to Skip to main content
Email Password   helpLost your password?

Introduction

This article is the second part of a series that provides JavaScript tips for ASP.NET developers. You can also read Part 1.

Background

There is no doubt that ASP.NET server controls make your life easy on the server-side. Third-party components like Karamasoft UISuite™ make it a lot easier on both server-side and client-side. However, you may still need some knowledge on client-side programming to provide your Web site visitors with a powerful user interface.

JavaScript is the most commonly used language for client-side programming regardless of your server-side development environment. Even though this article may be applied to other languages and frameworks, it is more appropriate for ASP.NET developers because most of the tips are accompanied with sample code in ASPX and C#.

Using the Code

  1. Cache your scripts
  2. Get inner text
  3. Toggle display
  4. Preload your images
  5. Concatenate your strings efficiently
  6. Use hash tables for efficient lookups
  7. Check whether an item exists in the array
  8. Retrieve query string values
  9. Move the focus away from your dropdown after change event
  10. Handle asynchronous operations with minimally growing arrays
  11. Pass data from one page to another using post

12. Cache Your Scripts

Using a JavaScript include file has several advantages compared to directly embedding JavaScript code inside a script block. The main advantage is that it provides code reuse by keeping the code in a central place. Another advantage is that your page size will be reduced significantly causing the page to be easier to maintain. Probably the most important advantage is caching by the browser. Subsequent requests to your page will retrieve the JavaScript library from the browser cache in order to load a lot faster.

You can place your JavaScript code in a *.js file, and include it in your Web pages using the following syntax:

<script src="KaramasoftUtility.js" type="text/javascript"></script>

13. Get Inner Text

Internet Explorer provides an innerText property to get or set the text between the start and end tags of the object. Firefox does not provide an innerText property but a textContent property to get or set the inner text. For the browsers that do not provide a property to get or set the inner text, you can clear the HTML tags inside the innerHTML property.

function GetInnerText(elem) {
 return (typeof(elem.innerText) != 'undefined') ?
    elem.innerText : (typeof(elem.textContent) != 'undefined') ?
    elem.textContent : elem.innerHTML.replace(/<[^>]+>/g, '');
}

14. Toggle Display

You can toggle the display of an HTML element easily by toggling its style display value between 'none' and ''.

JavaScript

function ToggleDisplay(elemId) {
 var elem = document.getElementById(elemId);
 elem.style.display = (elem.style.display != 'none') ? 'none' : '';
}

ASPX

<asp:LinkButton ID="lbToggleDisplay" runat="server"
    OnClientClick="ToggleDisplay('pnlToggleDisplay');
    return false;">Toggle Display</asp:LinkButton>
<asp:Panel ID="pnlToggleDisplay" runat="server">
Panel content here!
</asp:Panel>

15. Preload Your Images

If you want to display your images instantly when the page is loaded, you should preload your images using JavaScript in the HEAD section of your Web page. This technique also helps when you have rollover effects on your images where you display a different image when the mouse is over the image.

All you need to do is to create a new JavaScript Image object and set its src attribute to the path of your image.

<head runat="server">
<script type="text/javascript">
var img1 = new Image();
img1.src = '/Images/Product/UISuite.gif';
</script>
</head>

Note that you need to create new JavaScript Image objects for all the images you need to cache using different local variable names. To overcome this issue, you can use the following JavaScript function that takes the image paths as arguments and stores the JavaScript Image objects inside array elements.

<head runat="server">
<script type="text/javascript">
function PreloadImages() {
 var lenArg = arguments.length;
 if (lenArg > 0) {
  var imgArr = new Array();
  for (var i = 0; i < lenArg; i++) {
   imgArr[i] = new Image();
   imgArr[i].src = arguments[i];
  }
 }
}
PreloadImages('/Images/Product/UltimateEditor.gif',
    '/Images/Product/UltimateSearch.gif', '/Images/Product/UltimateSpell.gif');
</script>
</head>

This function takes as many image path arguments as you pass, creates a new JavaScript Image object for each of them and stores them in an array.

16. Concatenate Your Strings Efficiently

Even though it is easy to concatenate strings using the + operator, string operations become very costly in terms of CPU cycle when the strings get bigger and there are a lot of strings to concatenate.

The better alternative is to create your own StringBuilder JavaScript object that is similar to the StringBuilder object in the .NET Framework. You can define your StringBuilder object with a buffer array property to store the strings to concatenate. Then add an Append method to add a string to the buffer array. The JavaScript Array object provides a join method that puts all the elements of an array into a string separated by a specified delimiter. ConvertToString method will join all elements of the buffer array into a string.

function StringBuilder() {
 this.buffer = [];
}
StringBuilder.prototype.Append = function(str) {
 this.buffer[this.buffer.length] = str;
};
StringBuilder.prototype.ConvertToString = function() {
 return this.buffer.join('');
};

Instead of the following:

var str = 'This ' + 'is ' + 'a ' + 'test';

You can now use the following:

var sb = new StringBuilder;
sb.Append('This ');
sb.Append('is ');
sb.Append('a ');
sb.Append('test');
var str = sb.ConvertToString(); 

Our tests indicated that concatenating the string 'test' 50,000 times using the StringBuilder Append method worked 10 times faster than using the + operator in Internet Explorer.

17. Use Hash Tables for Efficient Lookups

Hash tables provide a way of efficient addition of new entries and the time spent searching for a specified key is independent of the number of items stored, which is O(1). Before explaining how to create a hash table in JavaScript, let's begin with a quick background about the associative arrays in JavaScript.

An associative array (hash) is an abstract data type composed of a collection of keys and a collection of values, where each key is associated with one value. In JavaScript, all objects are associative arrays. You can reach the object properties as follows:

document.forms['Form1']

or

document.forms.Form1

JavaScript objects do not provide a length property like Array object but you can iterate through the object properties using the following construct:

for (var prop in object)

For example, UltimateEditor component provides an associative array called UltimateEditors in the client-side API. Each UltimateEditor client-side object is defined as the property of UltimateEditors associative array. If you have multiple UltimateEditor components in your page, the following JavaScript code will iterate through all your UltimateEditor objects and display their HTML contents:

for (var ueObj in UltimateEditors) {
 alert(ueObj.GetEditorHTML());
}

We can now create our HashTable object using the associative array functionality. Our HashTable object will have two properties: hashArr property that stores key/value pairs and length property that keeps track of the number of items in the hash table. It will provide four methods:

  1. get method to retrieve the value for a given key
  2. put method to add a key/value pair to the hash table
  3. remove method to remove a key/value pair from the hash table
  4. has method to return whether given key value exists in the hash table
function HashTable(){
    this.hashArr = new Array();
    this.length = 0;
}

HashTable.prototype.get = function(key) {
    return this.hashArr[key];
};

HashTable.prototype.put = function(key, value) {
 if (typeof(this.hashArr[key]) == 'undefined') {
  this.length++;
 }
    this.hashArr[key] = value;
};

HashTable.prototype.remove = function(key) {
 if (typeof(this.hashArr[key]) != 'undefined') {
  this.length--;
  var value = this.hashArr[key];
  delete this.hashArr[key];
  return value;
 }
};

HashTable.prototype.has = function(key) {
 return (typeof(this.hashArr[key]) != 'undefined');
};

Now let's create a sample hash table for an efficient phone lookup:

var phoneLookup = new HashTable();
phoneLookup.put('Jane', '111-222-3333');
phoneLookup.put('John', '444-555-6666');
alert(phoneLookup.get('Jane'));

18. Check Whether an Item Exists in the Array

JavaScript Array object does not provide a built-in method to return whether a given value exists in the array. However, we can add a prototype method to extend Array functionality by adding a method to return whether the array has the given value.

Array.prototype.has = function(value) {
 var i;
 for (var i = 0, loopCnt = this.length; i < loopCnt; i++) {
  if (this[i] === value) {
   return true;
  }
 }
 return false;
};

Note that this method uses === operator to check if the value is identical (is equal to and is of the same type) to the value in the array. If you want to check only whether they are equal, you should replace === with == operator (is equal to).

Then, we can use this method as follows:

var arr = new Array();
arr[0] = 'test';
alert(arr.has('test')); // Should display true
alert(arr.has('test2')); // Should display false

19. Retrieve Query String Values

ASP.NET provides Request.QueryString collection that retrieves the values of the variables in the HTTP query string, but there is no built-in mechanism to retrieve query string collection on the client-side. However, you can parse the window location search property to get the query string values by using the GetAttributeValue method that we provided in one of our previous tips to center your window. Note that window.location.search property gets or sets the substring of the href property that follows the question mark.

function GetAttributeValue(attribList, attribName, firstDelim, secondDelim) {
 var attribNameLowerCase = attribName.toLowerCase();
 if (attribList) {
  var attribArr = attribList.split(firstDelim);
  for (var i = 0, loopCnt = attribArr.length; i < loopCnt; i++) {
   var nameValueArr = attribArr[i].split(secondDelim);
   for (var j = 0, loopCnt2 = nameValueArr.length; j < loopCnt2; j++) {
    if (nameValueArr[0].toLowerCase().replace(/\s/g, '') ==
            attribNameLowerCase && loopCnt2 > 1) {
     return nameValueArr[1];
    }
   }
  }
 }
} 

This method takes three arguments: a name/value pair list, the attribute name to retrieve its value, the first delimiter and the second delimiter. The first delimiter will be ampersand and the second delimiter would be equal sign to parse query string variables. Then you can use the following method to retrieve the query string value for given query string variable name.

function GetQueryStringValue(varName) {
 return GetAttributeValue
    (window.location.search.substring(1), varName, '&', '=');
}

20. Move the Focus Away from your Dropdown after Change Event

When the user changes the selection in a DropDownList, the focus remains inside the dropdown. If the user presses up/down arrow key or moves the mouse wheel, that action triggers the onchange event on the dropdown.

You can prevent this by making the dropdown lose focus in the onchange event.

JavaScript

function LoseFocus(ddlElem) {
 ddlElem.blur();
}

ASPX

<asp:DropDownList id="ddlLoseFocus" runat="server" AutoPostBack="true" />

C#

protected void Page_Load(object sender, EventArgs e)
{
ddlLoseFocus.Attributes.Add("onchange", "LoseFocus(this)");
}

21. Handle Asynchronous Operations with Minimally Growing Arrays

When you work with asynchronous AJAX callbacks, you might need to store the callback results in an array to process them later. The tricky part is to keep the array size at minimum. In order to do this, you can empty the array item when you are done with processing it and make it available for future callback results and always insert the new callback result to the first available array item.

function InsertActiveCallbackArr(arrayObj, arrayElem) {
 var i = 0;
 for (var loopCnt = arrayObj.length; (i < loopCnt) && arrayObj[i]; i++);
 arrayObj[i] = arrayElem;
}

When you are done with the callback result, simply set that array item to null.

function ProcessActiveCallbackArr(arrayObj) {
 for (var i = 0, loopCnt = arrayObj.length; i < loopCnt; i++) {
  // Process the callback result here
  // Then set the array item to null
  arrayObj[i] = null;
 }
}

22. Pass Data from One Page to Another using Post

If you need to pass small amounts of data from one page to another, you can pass it in the query string and the target page can retrieve it through Request.QueryString collection (GET operation). However, if you need to pass a large amount of data, you cannot pass it in the query string since Internet Explorer has maximum 2048 character limit on the address of the page. In these cases, you can pass data from one page to another using POST operation. In your source page, define a hidden variable to hold the data to pass and pass only its ID to the target page in the query string.

The target page should first get that ID through Request.QueryString collection. Then it should set its own hidden variable value with the one in the source frame on the client-side during BODY onload event handler. You can use opener object on the client-side to retrieve the DOM elements in the opener page. Then it should do a postback to itself and retrieve the value of its hidden variable through Request.Form collection.

Source Page JavaScript

function PassData(ctlID) {
 window.open('TargetPage.aspx?ctlID=' + ctlID, 'NewWindow', 'width=400,height=300,
    location=no,menubar=no,resizable=no,scrollbars=no,status=yes,toolbars=no');
}

Source Page ASPX

<asp:TextBox ID="txtPassData" runat="server" Text="Data to pass"
    CssClass="TextBox"></asp:TextBox>
<asp:Button ID="btnPassData" runat="server" Text="Pass Data"
    CssClass="Button" OnClientClick="PassData('txtPassData'); return false;" />

Target Page JavaScript

function Body_Onload() {
    var pageStatusElem = document.getElementById('hfPageStatus');

    // Page status hidden field value is initially empty string
    if (pageStatusElem.value == '') {
        // Set text to spell check hidden field value to the
        // text in the opener window
        document.getElementById('hfTextPassed').value =
            opener.window.document.getElementById
            ('<%=Request.QueryString["ctlID"]%>').value;

        // Set page status hidden field value so that when the page is posted back
        // it can process text to spell check retrieved from the opener window
        pageStatusElem.value = '<%=SET_TEXT%>';

        // Post back the page
        document.form1.submit();
    }
} 

Target Page ASPX

<body onload="Body_Onload()">
    <form id="form1" runat="server">
    <div>
    Text passed: <asp:Label ID="lblTextPassed" runat="server" Text="Label">
        </asp:Label>
    </div>
    <asp:HiddenField ID="hfTextPassed" runat="server" Value="" />
    <asp:HiddenField ID="hfPageStatus" runat="server" Value="" />
    </form>
</body>

Target Page C#

public const string SET_TEXT = "SetText";
public const string TEXT_IS_SET = "TextIsSet";

protected void Page_Load(object sender, EventArgs e)
{
 // Initial entry
 if (hfPageStatus.Value == SET_TEXT)
 {
  // Set page status not to enter again
  hfPageStatus.Value = TEXT_IS_SET;
 }
 lblTextPassed.Text = hfTextPassed.Value;
}
You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
QuestionIs there a system field that hold the value of the JavaScript Delimiter? : or $
smcirish
4:57 10 Mar '09  
In VS2003 the delimiter was :

Then when we migrated to VS2005, the JavaScript did not work. We found out later that the delimiter is now $

Is there a system field that holds the value of the delimeter? It would help with troubleshooting and debug.

smcirish
Texas

QuestionGetInnerText
Mon2
13:34 28 Feb '08  
I cannot get the GetInnerText to work it returns me JScript error = "Cannot assign to a function result"

what am i doing wrong.?
AnswerRe: GetInnerText
Mon2
19:03 28 Feb '08  
I have figured this out. I was trying to do something immposible. I wanted to have something like SetInnerText. I have created it with the help of your code.

thanks.
Question22 point
Chestozo
6:03 12 Oct '07  
Thank you for the article — it revealed some JS aspects for me.

I have a question: what is the purpose of using the mechanism, described at the 22 point?
Can't we achive the same effect by simple post back mechanism?
Maybe i misunderstood the key usage...
thank you.
AnswerRe: 22 point
Karamasoft
14:30 12 Oct '07  
Yes, you can postback from one page to another using cross-page postback mechanism which posts back all the form fields in the source page. The mechanism we provided was passing only a piece of data from one page to another by not using query string values as the way since there is a caharacter limit on the number query string (max 2048 characters in Internet Explorer) and it is less secure to see the critical data in the address bar of the browser. Hope this helps.
JokeRe: 22 point
Chestozo
21:03 12 Oct '07  
Ok now )))
The key point here is that we are using crosspage data passing and the only way to pass data from one page to another is the QueryString
Thank you! Smile
GeneralA+ article but...
Daniel Rendle
3:41 3 Oct '07  
What's the licensing for the code in both of your fine articles? Can I reuse it freely? (Please say yes! :->)
GeneralRe: A+ article but...
Karamasoft
7:49 3 Oct '07  
Yes, it's for free. Enjoy!
GeneralRe: A+ article but...
Daniel Rendle
4:02 4 Oct '07  
Woohoo! Big Grin Ta muchly! Smile
GeneralEasier get query string arguments
cmschick
20:08 2 Oct '07  
Hello,

Excellent article. I have a method which I like better for getting the query string arguments. Take a look at this:

function getArgs()
{
// Get the querystring arguments
var args = new Object();
var query = location.search.substring(1);
var pairs = query.split("&");
for(var i = 0; i < pairs.length; i++) {
var pos = pairs[i].indexOf('=');
if (pos == -1) continue;
var argname = pairs[i].substring(0,pos);
var value = pairs[i].substring(pos+1);
args[argname] = unescape(value);
}
return args;
}

Here's how it used:

var args = getArgs();

//Given this query string "MyPage.aspx?username=chris"
//The args will have the query string argument names as properties (i.e. args.username)
alert(args.username);

Chris Scihck
GeneralHashtable
J4amieC
0:51 27 Sep '07  
Your example of a Hashtable is not in fact anything like a hashtable. Its just an associative array, much more like a Dictionary in .NET than a Hashtable.




GeneralRe: Hashtable
Karamasoft
13:59 27 Sep '07  
Hashtable and Dictionary Collection Types in .NET both implement the same IDictionary interface. If you refer to http://msdn2.microsoft.com/en-us/library/4yh14awz.aspx[^] "The Dictionary class has the same functionality as the Hashtable class. A Dictionary of a specific type (other than Object) has better performance than a Hashtable for value types because the elements of Hashtable are of type Object and, therefore, boxing and unboxing typically occur if storing or retrieving a value type."

Hash table is an acronym for associative arrays as can be seen at http://en.wikipedia.org/wiki/Associative_array[^]

The bottom-line is our HashTable JavaScript implementation has the same lookup and insertion time (O(1)) of a hash table implementation.
GeneralYet another good article
merlin981
6:57 19 Sep '07  
5 from me



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I get my developer tools from Merlin A.I. Soft

Rhabot - World of Warcraft Bot

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Last Updated 27 Sep 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010