Monday, July 11, 2011


I have been writing web pages for a long time now. I started teaching HTML in 1999, and have worked for most of the last decade on projects that revolved around web pages. One would think that I probably knew most of the details of HTML - it is not a particularly complex language. Even if I didn't know all of the esoterica, surely I had all of the broad strokes, right? Well...

I was working on the accounting application within mypeoplematter. When the user needs to enter a transaction, they select an account from their chart of accounts. I am using a standard select list, which translates into a drop-down list in the web browser:

The list was too long (the basic chart of accounts has over 50 accounts in it), and there was no indication of the type of account (income / expense / bank / liability) in the list. I wanted to layout the list so that the account type was on the far-right, with the account name left-justified, but this is not supported by the HTML spec, so I was looking around the web for other ideas.

I found someone's code that had provided something like this, and was looking through it to try and understand what they did. In the midst of the code, there was something about optgroups. I didn't know what that was, so I googled it. Turns out, you can group items in select lists using optgroup. Over a decade of experience, and here was something new. Not only that, but it solves my problem perfectly. By the way, for programmers who find this, I will post at the end a small class that extends the standard .NET DropDownList to support retrieving the optgroup from the data source.

But my real point here is not about optgroups. My point is about knowledge. It seemed entirely reasonable to me to assume that I knew most of the features of HTML 4 - it is, after all, pretty simple. But here was something I had simply never encountered. It was a humbling moment. And of course, it made me realize that this experience is probably much more common than I realize. It is probably so for all of us. I know this is true: it just pays to be reminded:
It is not the things we know that give us the most trouble; it's not even the things we know we don't know; it's the things we don't know we don't know that are the biggest issue.
Humility doesn't always come easy for me. It's helpful to be reminded.

Programmers - here, in its entirety, is my DropDownList extension - it doesn't format well on my blog site, but if you select it and paste it into a text editor, it's all there:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using MyPeople.Extensions;


/// This class extends the built-in DropDownList to provide support for retriving the name of an optgroup from the database.
namespace MyPeople.WebControls {
    public class OptGroupDropDownList : DropDownList {
        public OptGroupDropDownList() { }

        /// The field in the datasource that provides the value for the optgroup. IF not set, then the list behaves as the built-in dropdownlist.
        public string OptGroupField {
            get {
                object o = ViewState["OptGroupField"];
                return (o == null) ? "" : (string)o;
            } // get
            set {
                ViewState["OptGroupField"] = value;
            } // set
        } // OptGroupField

        protected override void RenderContents(HtmlTextWriter writer) {
            if (String.IsNullOrEmpty(OptGroupField)) {
            } else {
                bool useOptGroup = !String.IsNullOrEmpty(OptGroupField);
                String lastOptGroup = null;
                ObjectDataSource ds = Page.MuchBetterFindControl(DataSourceID);
                IEnumerable objs = ds.Select();
                foreach (object item in objs) {
                    String text = DataBinder.Eval(item, DataTextField, DataTextFormatString);
                    String val = "";
                    if (!String.IsNullOrEmpty(DataValueField)) {
                        val = DataBinder.Eval(item, DataValueField, "{0}");
                    } // if
                    bool sel = false;
                    if (!String.IsNullOrEmpty(SelectedValue)) {
                        sel = val == SelectedValue;
                    } // if

                    if (useOptGroup) {
                        string thisGroup = DataBinder.Eval(item, OptGroupField, "{0}");
                        if (thisGroup != lastOptGroup) {
                            if (lastOptGroup != null) writer.WriteLine("");
                            writer.WriteLine("", thisGroup);
                            lastOptGroup = thisGroup;
                        } // if
                    } // if
                    writer.WriteLine("", System.Web.HttpUtility.HtmlEncode(text), System.Web.HttpUtility.HtmlEncode(val), sel ? " selected='selected'" : "");
                } // foreach

                if (useOptGroup) {
                } // if
            } // if
        } // RenderContents
    } // class OptGroupDropDownList
} // namespace

No comments: