To read the article online, visit http://www.4GuysFromRolla.com/articles/091008-1.aspx

Creating a Dynamic Data-Driven User Interface (Part 4)

By Scott Mitchell


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.

Customers can now specify whether a custom attribute is required or not.

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
If AttributeRequired Then
   ctrls.Add(CreateRequiredFieldValidator(DynamicAttributeId, "Required field."))
End If

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
   Dim rfv As New RequiredFieldValidator
   rfv.ID = "ReqVal_" & GetID(DynamicAttributeId)
   rfv.ControlToValidate = GetID(DynamicAttributeId)
   rfv.Display = ValidatorDisplay.Dynamic
   rfv.ErrorMessage = ErrorMessage

   Return rfv
End Function

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.

A RequiredFieldValidator is dynamically added to required custom attributes.

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
The String, Numeric, and Date data types render a TextBox control to capture the input. (The Numeric and Date data types also include a CompareValidator to ensure that the user's input is a valid numeric or date value.) The Boolean data type renders a CheckBox. Another common user interface for collecting input is the drop-down list, which allows the user to select one item from a pre-defined list of choices. This type of interface can be implemented but requires a bit more work than the other data types, both in defining the data type and in rendering the dynamic user interface. The download available at the end of this article has been extended to include a new data type named "Pick List."

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 NameData TypeNotes
DynamicPickListOptionIDuniqueidentifierPrimary key; default value of NEWID()
AttributeIduniqueidentifierA foreign key to DynamicAttributesForClients.DynamicAttributeId
DisplayTextnvarchar(50)The text to display in the drop-down list item
OptionValuenvarchar(50)A value associated with the drop-down list item
SortOrderint

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.

From this page customers can manage the pick list options for a particular attribute.

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.

The dynamic, data-driven user interface now includes the ability to add pick lists.

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!

  • By Scott Mitchell


    Attachments


  • Download the code used in this article

    Further Reading


  • Creating a Dynamic Data-Driven User Interface (Part 1)
  • Creating a Dynamic Data-Driven User Interface (Part 2)
  • Creating a Dynamic Data-Driven User Interface (Part 3)
  • Article Information
    Article Title: ASP.NET.Creating a Dynamic, Data-Driven User Interface (Part 4)
    Article Author: Scott Mitchell
    Published Date: September 10, 2008
    Article URL: http://www.4GuysFromRolla.com/articles/091008-1.aspx


    Copyright 2017 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers