Thursday, November 13, 2008

Creating a Dynamic Picklist Control

There are situations where you need to create a Picklist with values from an external source or just don’t want to keep a static list on the Picklist attribute. Initially I posted a simple solution which illustrates how to convert a text attribute into a Picklist.

This post offers a different and more robust solution to the creation of dynamic Picklists.
I call the control a TextList which obviously is a hybridization of a text and a Picklist fields.

The TextList also contains a Dependent Field Collection whose fields are bind to its onchange event. This way, each time the Picklist changes, the option properties are mapped to the form dependent fields. In the code sample bellow I’ve created 2 additional attributes on each option. The first is called Color and the second is called JustANubmer. When the user selects an option the color and number are written to two dependent fields (gi_dependentfield1 and gi_dependentfield2). The TextList also exposes other wrapper methods on the inner Picklist control so you won’t have to deal with two objects.

I’ve added comments which explain the methods functionality.


// JScript File
function OnCrmPageLoad()
{
/* Change gi_name text field to a textlist */
var nameTextList = new TextList( "gi_name" );
/* Set 2 dependent fields */
nameTextList.DependentFields.Add( "gi_dependentfield1" , "JustANumber" );
nameTextList.DependentFields.Add( "gi_dependentfield2" , "Color" );
/* Add blank option */
nameTextList.Add( "" , "" );
for( var i = 0 ; i < 6 ; i++ )
{
/* Fill some values */
var option = nameTextList.Add( "Text " + i , "Value " + i );
/* create 2 new attributes on each option (Color,JustANumber) */
option.Color = "A" + i + "B" + i + "C" + i;
option.JustANumber = i.toString();
}
/* Set the initial value */
nameTextList.SetInitValue(true);
/* Finish the job */
nameTextList.Transform();
}

/*
Holds a list of all dependent fields.
Each textlist has a dependent fields collection
*/
DependentFieldCollection = function()
{
this.List = [];
this.Add = function( name , prop ){
this.List.push( new DependentField( name , prop ) );
}
}
/*
Single Dependent Field.
The Object maps between an option attribute an a crmForm field
*/
DependentField = function( name , prop )
{
this.Property = prop;
this.Name = name;
}
/* Text list control */
TextList = function( txtId )
{
var textList = this;
/* Referech the original text field */
var textCtrl = crmForm.all[ txtId ];
if (!textCtrl) return alert("TextList: " + txtId + " Is Missing");

/* Create a new Picklist control */
textList.Picklist = document.createElement("SELECT");
textList.Picklist.id = textCtrl.id;
textList.Picklist.req = textCtrl.req;
textList.Picklist.tabIndex = textCtrl.tabIndex;
textList.Picklist.className = "ms-crm-SelectBox ";
textList.Picklist.defaultSelected = textCtrl.DataValue;
textList.DependentFields = new DependentFieldCollection();

/* Add the new picklist and remove the text control */
textCtrl.parentElement.appendChild( textList.Picklist );
textCtrl.parentElement.removeChild( textCtrl );

/*
Finish the textlist transformation
Create inline dependent fields properties on the textlist
Attach an update function to the picklist onchange event
*/
textList.Transform = function()
{
for( var i = 0;i < textList.DependentFields.List.length;i++ ){
var depField = textList.DependentFields.List[ i ];
textList[ depField.Name ] = crmForm.all[ depField.Name ];
}
textList.Picklist.attachEvent( "onchange" , UpdateDependentFields );
}
/* Sets the picklist value */
textList.SetValue = function( value )
{
textList.Picklist.DataValue = value;
textList.Picklist.FireOnChange();
}
/*
Sets the picklist initial value.
This should be called when the page load after you fill the picklist options
*/
textList.SetInitValue = function( fireEvent )
{
textList.Picklist.DataValue = textList.Picklist.defaultSelected;
if(fireEvent) textList.Picklist.FireOnChange();
}
/* Add a new picklist Option */
textList.Add = function( text , value )
{
return textList.Picklist.AddOption( text , value );
}
/* Remove a picklist Option by its value */
textList.Remove = function( value )
{
textList.Picklist.DeleteOption( value );
}
/* Clear all Picklist Options */
textList.Clear = function()
{
textList.Picklist.length = 0;
}
/* Helper property for attaching to an event from within the picklist control */
textList.Attach = function( targetId , eventName , callback )
{
var target = document.all[ targetId ];
if ( target ) target.attachEvent( eventName , callback );
}
/* Updates the dependent fields when the picklist onchange fires */
function UpdateDependentFields()
{
if ( textList.Picklist.selectedIndex > -1 )
for( var i = 0;i < textList.DependentFields.List.length;i++ )
{
var depField = textList.DependentFields.List[ i ];
textList[ depField.Name ].DataValue = textList.Picklist.SelectedOption[ depField.Property ];
textList[ depField.Name ].FireOnChange();
}
}
}


OnCrmPageLoad();

No comments: