webOS & a javaScript collection

Wow! It’s been a long time since I posted anything webOS related. In that time I’ve managed to get a couple of apps published – you can check them out here.

Quick Message (http://www.rahisi.co.uk/Product/QuickMessage)
TaskMaster (http://www.rahisi.co.uk/Product/TaskMaster)

Anyway, anything of interest? Yep, collections.

Whilst working on TaskMaster, I needed a collection class to wrap all the requirements up into one easy to manage class.
For example, one of the data sets includes a collection of people, and creating this via a javascript function gives a wrapper for managing them.

function person(name, title, age)
{
	this.name = name;
	this.title = title;
	this.age = age;
}

Putting these into a collection is easy enough using an array, but there’s a lot more functionality I could do with to manage these things easily enough.

What’s the basic functionality a collection needs?

  • Add ability
  • Delete
  • Count functionality

… and anything else that’ll make my life easier.

  • Sorting
  • Searching within the collection
  • A quick way to get data in and out of the depot.

OK, I’m going to dive straight in and not explain everything in intricate detail about how the thing works, so let’s start with the constructor. This is a standard javaScript function which contains a few properties including the underlying array (this.item).

function Collection(depot, dataName) {
	this.item = [];
	this.depot = depot;
	this.dataName = dataName;
};

Then add the basics for any collection. The Add function adds the new item to your collection and returns the new length.

Collection.prototype.Add = function(item){
	return this.item.push(item);
};

Count and length are the same functionality, but it makes it nice to be able to vary how the length is referenced. Coming from a .NET backgound, I prefer Count(), but either are allowed.

Collection.prototype.Count = function(){
	return this.item.length;
};

Collection.prototype.length = function(){
	return this.item.length;
};

Next I’ve added a range of delete functions. The first ,RemoveByIndex, will strip out an item at position [x] …

Collection.prototype.RemoveByIndex = function(index){
	if ((index>-1) && (index+1 <= this.item.length)){
		this.item.splice(index,1);
	}
};

… and RemoveByKey will remove an entry based on a property of the object. For example, delete the first entry where the age is 20. – collection.RemoveByKey(“age”,20);

Collection.prototype.RemoveByKey = function(keyname, keyvalue){
	var index =-1;
	for (var counter = 0; counter < this.item.length; counter++){
		if (this.item[counter][keyname] == keyvalue){
			index = counter;
			break;
		}
	}
	if (index > -1){
		this.RemoveByIndex(index);
	}
};

Clear immediately empties the contents of the collection…

Collection.prototype.Clear = function(){
	this.item = [];
}

… whereas Truncate will remove the last [x] number of items from the collection.

Collection.prototype.Truncate = function(limit){
	if((limit<0) || ( this.Count() <= limit)){
		return;
	}
	else{
		this.item.splice(limit);
	}
};

GetAll returns the underlying collection.

Collection.prototype.GetAll = function(){
	return this.item;
};

There are a number of functions to allow you to search the collection.
GetByKey() will return the first item that matches the key/value supplied [ e.g. item = collection.GetByKey(“age”,20) ]

Collection.prototype.GetByKey = function(keyname, keyvalue){
	var index =-1;
	for (var counter = 0; counter < this.item.length; counter++){
		if (this.item[counter][keyname] == keyvalue){
			index = counter;
			break;
		}
	}
	if (index > -1){
		return this.GetByIndex(index);
	}
	return null;
};

GetIndexByKey() will return the index of the first item that matches the key/value supplied [ e.g. itemIndex = collection.GetIndexByKey(“age”,20) ]

Collection.prototype.GetIndexByKey = function(keyname, keyvalue){
	var index =-1;
	for (var counter = 0; counter < this.item.length; counter++){
		if (this.item[counter][keyname] == keyvalue){
			index = counter;
			break;
		}
	}
	return index;
};

Finally, GetByIndex() will return an item at a specific index location. If you are outside of the range of the length of the collection, then null is returned.

Collection.prototype.GetByIndex = function(index){
	if ((index>-1) & (index+1 <= this.item.length)){
		return this.item[index];
	}
	return null;
};

Refresh provides a deep copy of the array from another source. It also allows the collection to be refreshed by passing itself in. The reason I added this was due to the fact I had issues updating a collection which has come from a data source in webOS. Any update to a collection populated straight from a DBSuccess call back didn’t update. Couldn’t figure this one out, but adding a refresh function to rebuild a list worked.

Collection.prototype.Refresh = function(source){
	this.Clear();
	if (source.length == 0){
		return;
	}
	var objectType = source[0].objectType;
	var objectClass = null;
	var objectInstance = null;
	var typeFound = false;
	if(objectType != "undefined"){
		objectClass = eval(objectType);
		typeFound = true;
	}
	for (var count = 0; count < source.length; count++)
	{
		if (typeFound){
			objectInstance = new objectClass(source[count]);
			this.Add( objectInstance);
		}
		else {
			this.Add( source[count] );
		}
	}
};

Sort will reorder the collection based on the key supplied (e.g. “age”), in either descending or ascending order. It is also possible to move all null values to the bottom of the collection. This uses the Swap function which is explained later.

Collection.prototype.Sort = function(keyname, order, nullsToBottom){
	if (this.Count() <2)
	{
		return;
	}
	if (typeof(keyname) == "string" )
	{
		keyname = new Array(keyname);
	}
	if (typeof(order) != "string" )
	{
		order = "asc";
	}
	if ((order != "asc") && (order != "desc"))
	{
		order = "asc";
	}
	var swapNeeded;
	for (var outerLoop = 0; outerLoop < this.Count(); outerLoop++)
	{
		for (var innerLoop = 0; innerLoop < outerLoop; innerLoop++)
		{
			if (innerLoop != outerLoop){

				swapNeeded = false;
				for (var keyCount = 0; keyCount< keyname.length; keyCount++)
				{
					if(( nullsToBottom ) &&
					   ((this.item[innerLoop][keyname[keyCount]] == null )&&
					   (this.item[outerLoop][keyname[keyCount]] !=null ))){
						swapNeeded = true;
						break;
					}
					if (order=="asc"){
						if (this.item[innerLoop][keyname[keyCount]] >
						    this.item[outerLoop][keyname[keyCount]]){
							swapNeeded = true;
							break;
						}
						else if (this.item[innerLoop][keyname[keyCount]]<
							 this.item[outerLoop][keyname[keyCount]]){
							break;
						}
					} else {
						if (this.item[innerLoop][keyname[keyCount]] <
						    this.item[outerLoop][keyname[keyCount]]){
							swapNeeded = true;
							break;
						}
						else if (this.item[innerLoop][keyname[keyCount]]>
							 this.item[outerLoop][keyname[keyCount]]){
							break;
						}
					}
				}
				if (swapNeeded){
					this.Swap(innerLoop, outerLoop);
				}
			}
		}
	}
	return;
};

Now for the additional stuff. Not necessary but the nice to haves. Update provides a quick way of updating a specific items property without actually accessing the item directly.
For example. collection.Update( collection.GetIndexByKey(“age”, 20″), “age”, 30); will update the first entry with an age of 20 to 30.

Collection.prototype.Update = function(index, field, value){
	this.item[index][field]=value;
};

Swap does exactly what it says.

Collection.prototype.Swap = function(index1, index2) {
	if ((index1 <= this.Count()) &&
	    (index2 <= this.Count())){

		var tempHold = this.item[index1];
		this.item[index1] = this.item[index2];
		this.item[index2] = tempHold;
	}
};

Finally, Save and Load provide quick access to the Depot.

Collection.prototype.Save = function(dbSuccess, dbFailure) {
	if ((this.depot) && (this.dataName))
	{
		this.depot.simpleAdd( this.dataName, this, dbSuccess, dbFailure);
	}
};

Collection.prototype.Load = function(dbSuccess, dbFailure) {
	if ((this.depot) && (this.dataName))
	{
		this.depot.get( this.dataName, dbSuccess, dbFailure);
	}
};

Although much of this functionality is already available in an array, I like to bring it all togther under an umbrella. If you feel this will be of use then feel free to use this and adapt it as necessary. It’s also worth noting there’s probaly a whole range of functionality that can still be added.

Advertisements
This entry was posted in javascript, Palm Pre Dev, WebOS. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s