Archives

Archives / 2010 / January
  • jQuery Code Does not have to be Ugly

    I never pass up a chance to look at jQuery code.  It’s amazing so much power can come from such a tiny package. 

    An appealing feature of jQuery is the browser independence it provides.  Every JavaScript book I’ve read, includes code for checking which version, of which browser, the code is running in.  There are a lot of:  if else—if else—if else….statements.  What a nightmare.  No thanks.  jQuery to the rescue!

    However, most of the jQuery code I’ve seen uses anonymous functions even when they aren’t needed which makes the code harder to read, buggier and less maintainable.  What a nightmare.  No thanks.  Note: I’m not anti-anonymous-functions; As a matter of fact, I use them in the code below (where appropriate).

    Here’s a jQuery sample:

    $(document).ready(function(){ 
        $("Input.DataEntry").each(function(){
            if (this.value == "")
                this.style.backgroundColor = "yellow";
            else
                this.style.backgroundColor = "White";
        });             
    });

    Putting that sample together took more than a few tries.  While it looks trivial, getting the curly braces and parenthesis to match up took some iterative trial and error.  Also, the debugger does not allow you to step into the code as it is written:  Instead, the debugger steps into the jQuery source code.  Yikes! 

    Here’s a cleaner way to connect a function to a jQuery event (Hint: don’t use an anonymous function):

    $(document).ready(DocReady);
     
    function DocReady()
    {       
           ColorCodeTextBoxes();
    }

    It is obvious what is being done in the code above…no problems with nesting curly braces and parenthesis.  When the document is ready, the DocReady function is called.  Let’s add a bit more code to show the advantages of doing it this way:

    // ---- Main Doc Ready function -----------------
     
    $(document).ready(DocReady);
     
    function DocReady()
    {       
        AssignClickToToggleButtons();
        ColorCodeTextBoxes();
    }
     
    // ---- ColorCodeTextBoxes -----------------------
    //
    // If a DataEntry textbox is empty, color it yellow
    // otherwise color it white.
    // To Do: use CSS classes instead of hard-coded color
     
    function ColorCodeTextBoxes()
    {
        var TextBoxes = $(":text.DataEntry");
     
        TextBoxes.each(function()
        {
            if (this.value == "")
                this.style.backgroundColor = "yellow";
            else
                this.style.backgroundColor = "White";
        });
    }
    // ---- AssignClickToToggleButtons -----------------------
    //
    // add function to Toggle buttons click event.
    // the function toggles the button's color with each click
     
    function AssignClickToToggleButtons()
    {
        $(".ToggleButton").click (function()
        {
            $(this).toggleClass('RedBackground').toggleClass('GrayBackground');
        })
    }

    Hooking up a standalone function to an event is better than jamming the contents of the function into the event as an anonymous function.  Here are some reasons why:

    • The function can be assigned to other events*.
    • The function can be debugged as a standalone object.
    • The function can be better commented.
    • The function can easily be removed, i.e.:  // ColorCodeTextBoxs();

    *In our example, you would want to Color Code the textboxes when the form loads and when it fails to submit to indicate which fields have been left blank.

    Some may point out that by chaining results and nesting functions you avoid intermediate variables.   To those people I give the Programmer’s Curse:  “Someday, I hope you have to maintain your own code.”

    Note that intermediate variables are absolutely mandatory when you are debugging: If you want to watch an object, you have to have something to watch.

    I do concede that intermediate variables and non-nested functions may make the code run a few nanoseconds slower.

    However, let me point out that just as real-estate agents have the phrase, “Location, Location, Location,” developers should adopt the phrase, “Maintenance, Maintenance, Maintenance.”

    I hope someone finds this useful.

    Steve Wellens

  • Serializing ArrayLists of Disparate Objects to XML Strings

    In an earlier post here, I wrote two functions to Serialize and Deserialize objects to XML strings.

    Since then, while reading a book about XML, I learned of even more power in the .Net XML Serialization libraries*. In addition to serializing objects and collections of objects you can serialize ArrayLists which can contain disparate or non-homogeneous objects. Techno-babble translation: Disparate and non-homogenous mean 'different'.

    *BTW: Never stop learning or you'll end up as geek road-kill on the nerd highway.

    I wrote two functions (in XMLUtils namespace) to encapsulate the logic. What do these functions do? Why I'd be delighted to show you. Here's an example of the functions in action:

    ArrayList MyArrayList = new ArrayList();
     
    MyArrayList.Add(new MyNameSpace.MyClass("Sue"));
    MyArrayList.Add(DateTime.Now);
    MyArrayList.Add(new MyClass("Bob"));
    MyArrayList.Add(1234);
     
    Response.Write("----- Before serialization ------ <br />");
    foreach (Object O in MyArrayList)
        Response.Write(O.ToString() + "<br />"); 
     
    String MyXml = XMLUtils.SerializeArrayList(MyArrayList);    // Serialize  
     
    MyArrayList = XMLUtils.DeSerializeArrayList(MyXml);         // Deserialize
     
    Response.Write("----- After deserialization ------ <br />");
    foreach (Object O in MyArrayList)
        Response.Write(O.ToString() + "<br />");
     
    // Output:
    //        ----- Before serialization ------ 
    //        Sue
    //        1/5/2010 12:50:15 PM
    //        Bob
    //        1234
    //        ----- After deserialization ------ 
    //        Sue
    //        1/5/2010 12:50:15 PM
    //        Bob
    //        1234
     
       

    The example shows an ArrayList being created with a custom class, a DateTime and an integer…disparate, non-homogeneous objects.

    The ArrayList is then serialized into an XML string.

    The XML string is then deserialized into a new ArrayList with all the objects intact.

    This could be useful…yah?

    To get this to work, one of the overloaded Serialize functions in the XmlSerializer class is used. The Serialize function is passed an array of types to be serialized. It is easy to get all the types in the ArrayList by iterating the list.

    The problem is deserializing the list. How do you get the array of types the deserializer needs?

    My Solution: Add the list of types in the ArrayList…to the ArrayList…before serializing it.

    The solution has one drawback: Deserialization happens twice. The XmlString is deserialized to get the array of types. Once the array of types is collected, the XmlString is deserialized again with the array of types and the ArrayList will be reconstituted correctly. The XmlString could be parsed to get the array of types but it would probably be just as slow as deserializing and definitely more complicated. The list of types could be included as auxiliary information in a custom class but my self-imposed requirement was to serialize to a valid XML document which requires a single root element…so the list of types must be within the root element.

    Here are the functions:

    /// ---- SerializeArrayList ----------------
    /// <summary>
    /// Serialize an ArrayList to an XML string
    /// </summary>
    /// <param name="ArrayListIn">An ArrayList</param>
    /// <returns>XML String</returns>
     
    public static string SerializeArrayList(ArrayList ArrayListIn)
    {
        // get a list of all the types in the ArrayList to serialize
        // avoid duplicates
        ArrayList TypesInList = new ArrayList();
     
        foreach (Object Item in ArrayListIn)
        {
            if (TypesInList.Contains(Item.GetType()) == false)
                TypesInList.Add(Item.GetType());
        }
     
        // we're going to add a string array, so add these two types
        if (TypesInList.Contains(typeof(String)) == false)
            TypesInList.Add(typeof(String));
        if (TypesInList.Contains(typeof(String[])) == false)
            TypesInList.Add(typeof(String[]));
     
        // Convert the list of types to a string array of type names
        // so we can add it to the ArrayList
        String[] TypeNamesArray = new String[TypesInList.Count];
     
        for (int i = 0; i < TypesInList.Count; i++)        
            TypeNamesArray[i] = ((Type)TypesInList[i]).AssemblyQualifiedName;
     
        // add the array of type names to the ArrayList
        ArrayListIn.Add(TypeNamesArray);
     
        // The Serialize function require an array of type objects
        Type[] Types = (Type[])TypesInList.ToArray(typeof(Type));
     
        // create the serializer, give it the ArrayList type and 
        // the array of types in the ArrayList
        XmlSerializer Serializer = new XmlSerializer(typeof(ArrayList), Types);
     
        // create a stream for the Serializer output
        StringWriter Writer = new StringWriter();
     
        // Do the Serialization
        Serializer.Serialize(Writer, ArrayListIn);
     
        String XMLString = Writer.ToString();
     
        // remove the string array of types we added.
        // we don't want to affect the original list.
        ArrayListIn.RemoveAt(ArrayListIn.Count - 1);
        return XMLString;
    }
     
    /// ---- DeSerializeArrayList --------------------------------------
    /// <summary>
    /// Deserialize an XML string to an ArrayList that was
    /// serialized with the SerializeArrayList function.
    /// </summary>
    /// <param name="XmlString">XML String to deserialize</param>
    /// <returns>A populated ArrayList</returns>
     
    public static ArrayList DeSerializeArrayList(String XmlString)
    {
        // extract the array of type names
        // it's the last node of the ArrayList
        Type[] TempTypes = new Type[2];
     
        TempTypes[0] = typeof(System.String);
        TempTypes[1] = typeof(System.String[]);
        XmlSerializer Serializer = new XmlSerializer(typeof(ArrayList), TempTypes);
     
        ArrayList MyArrayList;
     
        // create a stream for the DeSerializer input
        StringReader StrReader = new StringReader(XmlString);
     
        // first deserialization (we'll do this again)
        MyArrayList = Serializer.Deserialize(StrReader) as ArrayList;
     
        // get the array of type names (last node in ArrayList)
        String[] StrTypes = MyArrayList[MyArrayList.Count - 1] as String[];
     
        // convert it to an array of type objects
        TempTypes = new Type[StrTypes.Length];
        for (int i = 0; i < TempTypes.Length; i++)
            TempTypes[i] = Type.GetType(StrTypes[i]);
     
        // create the serializer, this time with a complete array
        // of the types contained in it.
        Serializer = new XmlSerializer(typeof(ArrayList), TempTypes);
     
        // create a stream for the DeSerializer output
        StrReader = new StringReader(XmlString);
     
        // Deserialize
        MyArrayList = Serializer.Deserialize(StrReader) as ArrayList;
     
        // get rid of the array of type names, we put it
        // there and it's not part of the orginal ArrayList
        MyArrayList.RemoveAt(MyArrayList.Count - 1);
        return MyArrayList;
    }

    I put the functions in a namespace called XMLUtils (in a file called XMLUtils.cs). You can download the file here. It also includes updated versions of the two functions to serialize and deserialize single objects from an earlier post.

    Note: The classes and namespaces of the objects in the ArrayList must be available in the scope of where the serialization and deserialization takes place.

    Note: I initially tried to serialize an array of Types instead of an array of Type Names. But the serializer did not like that. It didn't like it one bit.

    Note: I could have created the functions as extension methods or added an extension method wrapper like this:

    public static string ExSerializeArrayList(this ArrayList ArrayListIn)
    {
        return SerializeArrayList(ArrayListIn);
    }

    But, to be symmetric, an Extension method would need to be created for the String class and that would burden the often-used String class with a very specialized and rare usage… so it was not done.

    I hope someone finds this useful.

    Thanks,

    Steve Wellens