Friday, February 13, 2009

Correction - Customized Input Forms: The JavaScript Approach

Previously I posted about my method for customizing SharePoint list forms (NewForm.aspx, DispForm.aspx, EditForm.aspx). Recently, an issue has come up with respect to this code and saving list items.

If a user is modifying a list item, and they have disabled controls on the page (grayed out), then when they save the item, those disabled fields will revert to the default value specified for each of those columns. The correct values populate on the page, but apparently the values stored within disabled controls do not get returned to the server upon the form being submitted.

I have come up with a quick solution (not sure if it is the best at this moment), but it allows for the values to be returned to the server by re-enabling all of the disabled fields just before the form is submitted. Only problem so far is that if the page takes a while to submit, the fields appear to be editable to the user, even though changes made won't actually be sent to the server.

Please see this link for a reference to the function PreSaveAction(): Add JavaScript Date Validation into List Item forms

Updated code (new code added is highlighted in yellow): CustomizedInputForms_JavaScriptFile

Enjoy!
--andrew

MOSS Cascading DropDownLists - The Sexy Approach - 2 of 2

Disclaimer reiterated: Do NOT copy/paste all of this code and deploy straight to a production environment. I cannot stress this enough.

Link to previous post: MOSS Cascading DropDownLists - The Sexy Approach - 1 of 2

Welcome to the second half of my discussion about AJAX Cascading DropDownLists within SharePoint 2007. I apologize for not getting this posted earlier, but I've been swamped at work lately. There is a lot of code involved, and I would like to thank the following people for various bits and pieces which I borrowed (links to my code are at the bottom of the post):


As the manifest.xml and wsp_structure.ddf files are pretty straightforward if you've worked with SharePoint Solution packages before, I will not discuss these.

Here is a great walkthrough on the different elements required in creating a custom field type on MSDN: Walkthrough: Creating a Custom Field Type.

We'll start with the creation of the field type definition: fldtypes_cascadingdropdownlist.xml. This file is used to store the various configuration information related to your custom field type. Multiple field types can be defined within the same file, however, this is not advised. All of the fields at the top are standard custom field type definition attributes.
  • TypeName is the internal name for this field type
  • TypeDisplayName is what will be displayed on the "Create a new column" page
  • FieldTypeClass is where you reference the assembly containing your field type class
  • FieldEditorUserControl is the location of the ASCX file which defines the user interface for Custom Properties
  • PropertySchema is used to define custom properties.
    All of my custom properties are simple TEXT fields, which have fixed length and are hidden. This is so I can use other controls (like DropDownLists) for the creation of the column, to make selecting values easier on the user. These custom properties are where I store which list supplies the data and how it is displayed/filtered.
  • RenderPattern is not used in my solution.

The class and assembly referenced in the attribute FieldTypeClass is used as the base class for storing/retrieving custom and default properties for this field type. Please see the comments in CascadingDropDownList.cs for a more detailed breakdown of functionality. I have opted to use the ThreadData method for storing values on initial column creation as mentioned previously in the MSDN article by Wouter van Vugt.

In CascadingDropDownList.cs near the bottom, I am using the custom class CascadingDropDownListEditControl as the RenderingControl. The user control for this is incredibly simple: CascadingDropDownListEditControl.ascx. It is just a normal DropDownList inside of a SharePoint RenderingTemplate. The class file associated with this ASCX file is CascadingDropDownListEditControl.cs. There are a few key components of this class to note:
  • ddlCascading.ContextKey is used to pass the necessary information to access a SharePoint list to the Web Service which will be populating the DropDownLists on the client side.
  • ddlCascading.ParentControlID has to be set at runtime, as this is the ID of the control on the page, not the value stored within the column's properties.
  • Render method is overridden to circumvent the necessity of disabling EventValidation for the CascadingDropDown extender to function. This method obtains all possible values from the corresponding SharePoint lists, and registers them for event validation on the client side (potential performance hit if you have significantly large value lists).
  • ddlCascading.ServicePath is the location for the web service to pass the AJAX request to and ddlCascading.ServiceMethod is the method invoked within the given Web Service.

This web service is defined within the files CascadingWebService.asmx and CascadingWebService.cs. The ASMX file is very simple, with just a reference to the assembly containing the web service class. Within the class, there are two functions: GetListItemsPageMethod and SortNameValuePair. The name for GetListItemsPageMethod can vary as long as it is the same here as it is in CascadingDropDownListEditControl.cs for ddlCascading.ServiceMethod. However, the *signature* for this method must be exactly as displayed. The contextKey at the end is optional (if you don't have to supply additional information for the AJAX request), but the rest of the parameters, as well as the security modifier and return type must be the same as I've used. SortNameValuePair, on the other hand, is a custom function I created to allow for sorting the collection of CascadingDropDownNameValues, since List.Sort does not know how the name-value pairs should be compared.

And the final component to this solution is the Properties class for the Cascading DropDownList. The Properties class is used for defining the way in which custom list properties (specified within the field type definition fldtypes_cascadingdropdownlist.xml) are displayed on the column creation/modification page. Again, please reference the comments within CascadingDropDownListPropControl.cs for a description of what is happening. It displays and modifies the custom column properties (which are defined as TEXT elements) using a Text Box, a Button, and several DropDownLists. CascadingDropDownListPropControl.ascx is a little more involved than the other ASCX files, but much of the HTML was simply to ensure that the properties for this custom field control looked like the properties for out-of-the-box field controls.

For the Name/Value columns, the source SharePoint list needs to be established as follows:
  • For each Cascading DropDownList you plan to have, you need a column to represent its potential values.
  • Be sure to enter all possible values for Parent, Child, Grandchild, etc within each list item
  • Here is a picture of my sample list: Bird Classifications

I tried to supply a lot of code, with the hope that it would be self-explanatory. If you need further explanation of what is happening, or why I did it this way, please do not hesitate to comment below. Here are some pictures of a sample implementation for Bird Sightings, using 3 Cascading DropDownLists (Family[Parent] -> Genus[Child] -> Species[Grandchild]):

Limitations:
  • The Cascading DropDownList controls must be displayed in order on the page, in the order you want their relationship to be (Parent before Child, and Child before Grandchild, etc.) If the Child is before the Parent, then the Child control will not be able to find the Parent control on the page.
  • It is possible to modify the Parent field of a Cascading DropDownList to a control which appears lower on the form page. The filtering of values in the "Parent Column" property only removes the current field.
  • If you have a Parent->Child->Grandchild relationship, and different Parent values have the same Child values in the source SharePoint list, then all of the potential Grandchildren for each Child will be visible if that Child is selected, regardless of which value is entered into Parent.

This control has already received widespread use within my organization. If you have any recommendations on improvement to remove these limitations, I would love to hear about the modifications you have made to the below code. I hope you enjoyed this deep-dive into employing the AjaxControlToolkit's CascadingDropDown within SharePoint using a Custom Field Control.

Enjoy!
--andrew

Links to solution files: