Creating a Dynamic Data-Driven User Interface (Part 4)
By Scott Mitchell
| Creating a Dynamic, Data-Driven User Interface |
|---|
|
This article is one in a series of articles on building a web application that supports dynamic, data-driven user interfaces.
|
Introduction
This article is the fourth and final installment of a series that examines how to build a data-driven web applications that offers dynamic user interfaces. Over the past three articles we created a sample web application that allows for numerous law firms to log in to the site and manage their clientele. Client data is dispursed across fixed and dynamic data models. The fixed data model contains a set of client attributes common to all law firms -
FirstName, LastName, Email, and so forth - while the dynamic data model allows
each law firm to define their own custom client attributes. For example, a personal injury firm could include attributes like Date Injured, and
Was Permanently Disabled, while a law firm specializing in bankruptcy would have attributes like Debt Servicing Cost and Monthly Income Amount.
A completely functional demo was constructed over the past three installments. Part 1 examined the scope of the project and created the data model. Part 2 showed how to allow customers (law firms) to define their custom client attributes. And Part 3 looked at dynamically building the user interface for collecting custom client attributes. While the web application created over the past three tutorials offer a true dynamic, data-drive user interface, there are several places that could be improved upon. This final installment reviews some of these enhancements with a discussion on how to implement each of them. Read on to learn more!
Including Validation Rules for Custom Client Attributes
The
DynamicAttributesForClients table contains a record for each custom client attribute defined in the system. Each custom client attribute
must express, at a minimum, what customer the client attribute is associated with, the data type (String, Date, etc.), and the name of the custom
attribute. The DynamicAttributesForClients table has columns for these fields as well as a SortOrder column, which allows the
customer to define the order with which the custom attributes appear when managing the custom client attributes in ~/Customers/ClientCustomAttributes.aspx.
When defining a custom client attribute a customer (the law firm) may want to include validation rules. For example, when a personal injury law firm
defines a custom attribute named Date Injured of type Date they may also want to indicate that this value is required and must be less than or equal
to the current date. These validation rules can be specified through additional columns in the DynamicAttributesForClients table, and then
implemented as dynamically-added validation Web controls in ~/Customers/ClientCustomAttributes.aspx. To demonstrate how this works, let's
augment the functionality created in Part 3 to include the ability for customers to optionally mark custom attributes as required.
Start by adding a new column to the DynamicAttributesForClients table named Required as a bit data type
that doesn't allow NULLs and has a default value of 0. Next, open the ~/Customers/DefineClientAttributes.aspx page in Visual Studio.
Recall that this page is used by the customer to define their custom client attributes. Update the page to incorporate the new Required
column. The following screenshot shows this page after the DetailsView and GridView and SqlDataSource control has been updated accordingly. As you
can see, I've marked the Birthdate, Married, and Reason for Law Suit custom attributes as required and have left the Employed and Number of Years
at Current Job custom attributes as optional.
Note that from this interface I can mark Boolean custom attributes such as Married as required. However, because our user interface uses a CheckBox
for Boolean attributes the concept of "required" really doesn't make sense. You can't have a "required" CheckBox, after all. You might, then, want to
consider enhancing the UI in ~/Customers/DefineClientAttributes.aspx to hide the Required CheckBox in the GridView for attributes of
type Boolean. I leave this as an exercise for the interested reader.
The final piece of the puzzle is to update the code that generates the dynamic, data-driven user interface to include validation Web controls for required
custom attributes. Recall that Web controls that are dynamically added to the the ~/Customers/ClientCustomAttributes.aspx page are done
so in the CreateCustomAttributeUI method. This method adds a multi-line TextBox Web control for custom attributes of type String, a
CheckBox for custom attributes of type Boolean, and so on. We need to update this method to add a RequiredFieldValidator to the control hierarchy
for each required custom attribute.
Adding a RequiredFieldValidator to the necessary custom attributes is straightforward. Start by augmenting the CreateCustomAttributeUI method
to accept a new input parameter named AttributeRequired of type Boolean. (You'll need to update the code in the
Page_Init event handler to retrieve the Required column value along with the other columns from the DynamicAttributesForClients
table, and to pass this value along to the CreateCustomAttributeUI method via the AddCustomAttribute method.) The following
snippet of code adds the RequiredFieldValidator:
'Add a RequiredFieldValidator, if needed
|
This method calls the CreateRequiredFieldValidator method (shown below) and adds it to the control collection that is added to the
page's control hierarchy. The CreateRequiredFieldValidator method creates a new RequiredFieldValidator instance, sets its germane properties,
and returns the validation control object.
Private Function CreateRequiredFieldValidator(ByVal DynamicAttributeId As Guid, ByVal ErrorMessage As String) As RequiredFieldValidator
|
Keep in mind that the RequiredFieldValidator cannot be added to a CheckBox control. Therefore, we do not want to add the RequiredFieldValidator
when dealing with a control of type Boolean. If you download the demo available at the end of this article and inspect the code in the
CreateCustomAttributeUI method you'll find the If AttributeRequired Then... code appears in each data type Case statement
except for Boolean.
The following screenshot shows the RequiredFieldValidator controls in action. Note that if a user omits the Birthdate or Reason for Law Suit fields a warning is displayed and the form cannot be submitted.
This concept of defining and implementing a required validation rule could be replicated to allow additional validation rules.
Custom Attributes that Enable a User to Pick an Option from a Set of Pre-Defined Choices
Each custom attribute created by a custom must have an associated data type. The data type determines how the attribute's user interface is rendered. In Part 1 we defined four data types in the
DynamicAttributeDataTypes table:
- String
- Boolean
- Numeric
- Date
In order to include a "pick list" data type we need to allow customers to define the set of legal choices for a particular custom attribute. To capture
this set of choices we need to add a new table to the database. I created a table named DynamicPickListOptions with the following schema:
| Column Name | Data Type | Notes |
|---|---|---|
DynamicPickListOptionID | uniqueidentifier | Primary key; default value of NEWID() |
AttributeId | uniqueidentifier | A foreign key to DynamicAttributesForClients.DynamicAttributeId |
DisplayText | nvarchar(50) | The text to display in the drop-down list item |
OptionValue | nvarchar(50) | A value associated with the drop-down list item |
SortOrder | int |
The AttributeId column ties the pick list options back to a particular custom attribute. For example, consider a custom client attribute
named "Payment Options." If there were three options - Pro Bono, On Retainer, and Paid/Hour - there would be three records in the
DynamicPickListOptions table, all pointing back to the same attribute, "Payment Options."
The OptionValue is meant to associate additional information with a particular drop-down list choice. This column value might be useful
in reporting or other endeavors. It is not used to directly indicate the selected value, however. Instead, the DynamicPickListOptionID
column value is used. For instance, if a particular client is paying per hour, and the Paid/Hour option in DynamicPickListOptions
has a DynamicPickListOptionID value of 0477a3a3-4793-4247-8b37-ad756b8cd367, then there will be a record in the
DynamicValuesForClients table whose DynamicValue column value is 0477a3a3-4793-4247-8b37-ad756b8cd367. The
value of the OptionValue column for Paid/Hour is immaterial here.
The user interface for defining custom client attributes needs to be updated. In particular, we need a page where a user can define the choices
for a particular pick list attribute. To handle this, I added a new page to the web application in the Customers folder named
EditPickListOptions.aspx. This page is passed the DynamicAttributeId of the attribute whose options to manage through
the querystring, and then displays a DetailsView and GridView to allow inserting, updating, and deleting of the pick list options. The screenshot
below shows this page in action.
I also updated the DefineClientAttributes.aspx page to include a link in the GridView titled "Edit Pick List Options," which points to
EditPickListOptions.aspx?ID=DynamicAttributeID. This link is only displayed for attributes of type "Pick List."
I also updated the CreateCustomAttributeUI and GetValueForCustomAttribute methods in ClientCustomAttributes.aspx,
which are the methods that are used to dynamically create the user interface and retrieve the user-entered values, respectively.
CreateCustomAttributeUI now adds a DropDownList control for attributes of type Pick List. It populates the DropDownList with the
set of options defined for the custom attribute; it also includes a "-- Select One --" option. If the custom attribute is marked as a required attribute
then a RequiredFieldValidator is added with its InitialValue property set to the value of the "-- Select One --" option.
The GetValueForCustomAttribute method gets the DropDownList (via the FindControl method). If the "-- Select One --" option
is selected then a database NULL value is used for the DynamicValue in the DynamicValuesForClients table. Otherwise, the
option's corresponding DynamicPickListOptionID value is used.
Conclusion
Over the course of this article and the past three we have created a fully-functional dynamic, data-driven user interface. Whew! In this concluding installment we looked at two ways to enhance the functionality of the custom attributes: by defining validation rules and by including additional data types. There are still many places where the system can be improved, however. Right now, our Pick List data type allows the user to choose only one option from a list of choices, but what if we need to let them select multiple options?
Another issue we haven't covered is how to handle editing and deleting of custom attributes. For instance, what happens if a user deletes a pick list option that is assigned to various
clients? Or what if the name or data type of an attribute is changed? The simplest approach is to prohibit users from renaming attributes or reassigning
their data type. A more sophisticated approach would allow such changes to happen, but only for attributes that don't have values for any clients.
Moreover, it's prudent to disallow attributes or pick list options to be deleted, and to instead include a Discontinued field. This
allows a user to flag what attributes or pick list options should no longer appear in the user interface without losing the values already assigned to
clientele.
Happy Programming!
Attachments
Further Reading




