Chad Scharf's Weblog
It's always time to upgrade!

Creating a JavaScript HashTable

Friday, 2 May 2008 16:10 by Chad

I use a lot of configuration and provider driven services and variables for developing web applications. Let's face it, I don't like to recompile. I recently had the need to share my Web.config settings with the client code, but didn't want to declare a variable for every possible setting, I just wanted to dynamically create the script of configuration settings in some collection and have access to that in my client side code. Because I wanted this collection to act just like a HashTable in System.Collections, I decided to create a JavaScript type to mirror the storage and access paradigm of the HashTable for use in my applications.

The Storage Container

The basic structure of the HashTable is comprised of an enumerable collection of KeyValuePair objects. To mimic this, I had to define my KeyValuePair object on the client. I decided to use Microsoft's AJAX Client Library included in the .NET 3.5 Framework.

KeyValuePair = function(key, value) {
KeyValuePair.initializeBase(this);
// Add custom initialization here
    this._key = key;
    this._value = value;
}
KeyValuePair.prototype = {
    // Returns the current Dialer Status key
    get_key : function() {
        return this._key;
    },
    set_key : function(key) {
        this._key = key;
    },
    // Returns the next to execute Dialer Command
    get_value : function() {
        return this._value;
    },
    set_value : function(val) {
        this._value = val;
    },
initialize: function() {
KeyValuePair.callBaseMethod(this, 'initialize');
},
dispose: function() {
KeyValuePair.callBaseMethod(this, 'dispose');
}
}
KeyValuePair.descriptor = {
properties: [ {name: 'key', type: String},
{name: 'value', type: String} ]
}
KeyValuePair.registerClass('KeyValuePair', Sys.Component);

I then had to create the container to wrap a collection, or in JavaScript's case an Array, of these KeyValuePair objects and make them indexed, searchable, and easy to use just like the .NET HashTable class.

HashTable = function() {
HashTable.initializeBase(this);
// Add custom initialization here
    this._items = new Array();
    this._deletedIndexes = new Array();
    this._isDeleted = function(index) {
        for (var i = 0; i < this._deletedIndexes.length; i++) {
            if (this._deletedIndexes[i] == index) {
                return true;
            }
        }
        return false;
    }
}
HashTable.prototype = {
    // Returns the next to execute Dialer Command
    get_value : function(key) {
        for (var i = 0; i < this._items.length; i++) {
            if (!this._isDeleted(i)) {
                var item = this._items[i];
                if (item.get_key() == key){
                    return item.get_value();
                }
            }
        }
        return null;
    },
    set_value : function(key, val) {
        for (var i = 0; i < this._items.length; i++) {
            if (!this._isDeleted(i)) {
                var item = this._items[i];
                if (item.get_key() == key){
                    item.set_value(val);
                    this._items[i] = item;
                }
            }
        }
    },
    get_count : function() {
        return this._items.length;
    },
initialize: function() {
HashTable.callBaseMethod(this, 'initialize');
},
dispose: function() {
        this._items = null;
HashTable.callBaseMethod(this, 'dispose');
},
addPair : function(pair) {
        if (pair == null) { return; }
        var exists = this.get_value(pair.get_key());
        if (exists) { return; }
        this._items.push(pair);
},
remove : function(key) {
        for (var i = 0; i < this._items.length; i++) {
            if (!this._isDeleted(i)) {
                if (this._items[i].get_key() == key){
                    this._items[i].set_key(null);
                    this._items[i].set_value(null);
                    this._deletedIndexes.push(i);
                    return;
                }
            }
        }
},
addItem : function(key, value) {
        this.addPair(new KeyValuePair(key, value));
}
}
HashTable.descriptor = {
properties: [ {name: 'count', type: Number} ]
}
HashTable.registerClass('HashTable', Sys.Component);

And that's it! With this new client component I can store configuration entries on the client for use by my page's script. I simply do the following on the server, in my code behind in order to create the collection itself.

Client:

// Declare our global config variable
var Config = new HashTable();

ASP.NET Form:

<%=GetConfigScript()%>

Server:

public string GetConfigScript()
{
    StringBuilder script = new StringBuilder();
    script.AppendLine("<script type=\"text/javascript\">");
    script.AppendLine("//<![CDATA[");
    foreach (string key in ConfigurationManager.AppSettings.AllKeys)
        script.AppendFormat("Config.addItem(\"{0}\",\"{1}\");",
            key.Replace(@"\", @"\\"),
            ConfigurationManager.AppSettings[key].Replace(@"\", @"\\"));
    script.AppendLine("//]]>");
    return script.ToString();
}

Conclusion

Now, whenever I want to access a configuration setting on the client, I call Config.get_value("key"); and it returns that value or null, just like using Configuration.AppSettings["key"] or a HashTable to store values by key, I just happened to use it for configuration settings but it could be used any time I need a searchable HashTable for storing key-value pairs.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Related posts

Add comment


(Will show your Gravatar icon)  

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

September 7. 2008 16:43