Sunday, July 27, 2008

Simplifying CRM UI development

This is a utility class which incorporates common tasks developers usually endure while developing mscrm solutions.

Spec:

CRMField.Disable() - Disable Field
CRMField.Enable() - Enable Field

CRMField.HideCell() - Hide Cell ( field + label )
CRMField.ShowCell() - Show Cell

CRMField.HideRow() - Hide Entire Row
CRMField.ShowRow() - Show Entire Row

CRMField.Required() - Make Field Required *
CRMField.Level() - Get Field Required level

CRMField.NotRequired() - Make Field Not Required

CRMField.Changed() - Returns whether the Field was changed since it was loaded
CRMField.IsEmpty() - Checks whether the Field is null or empty("")

CRMField.Alert() - Helper function - Alerts the Field DataValue
CRMField.OnChange( OnFieldChangeEvent ) – Attaches a function to the Field OnChange Event
CRMField.ReLabel( "New label" ) - Change Field label (HTML)

CRMField.InitValue - Holds the Field Initial Value
CRMField.LastValue - Holds the Field Last value before it was changed

CRMField.First() - Revert to the Field Initial Value
CRMField.Last() - Revert to the Field Last Value


Paste the CrmField class inside the entity onload event or global.js (unsupported).


function CrmField( fieldId )
{
var crmField = this;

crmField.Id = fieldId;
if( crmField.Id == null || crmField.Id == "" ) return;

crmField.Field = document.getElementById(fieldId);
if( this.Field == null ) return;

crmField.InitValue = crmField.Field.DataValue;
crmField.LastValue = "";
crmField.Cell = document.getElementById(this.Field.id + "_d");
crmField.Label = document.getElementById(this.Field.id + "_c");
crmField.Row = crmField.Cell.parentElement;
crmField.Disable = function(){ crmField.Field.Disabled = true; }
crmField.Enable = function(){ crmField.Field.Disabled = false; }
crmField.HideCell = function(){
crmField.Field.style.visibility = "hidden";
crmField.Cell.style.visibility = "hidden";
crmField.Label.style.visibility = "hidden";
}
crmField.HideRow = function(){ crmField.Row.style.display = "none"; }
crmField.ShowCell = function(){
crmField.Field.style.visibility = "visible";
crmField.Cell.style.visibility = "visible";
crmField.Label.style.visibility = "visible";
}
crmField.ShowRow = function() { crmField.Row.style.display = "inline"; }
crmField.Required = function() { crmForm.SetFieldReqLevel(crmField.Id,true); }
crmField.NotRequired = function(){ crmForm.SetFieldReqLevel(crmField.Id,false); }
crmField.Level = function() { return crmField.Field.RequiredLevel; }
crmField.Changed = function() { return crmField.Field.IsDirty(); }
crmField.IsEmpty = function() { return (crmField.Field.DataValue == null); }
crmField.Alert = function() { alert(crmField.Field.DataValue); }
crmField.Last = function() { crmField.Field.DataValue = crmField.LastValue; }
crmField.First = function() { crmField.Field.DataValue = crmField.InitValue; }
crmField.OnChange = function(f){ crmField.Field.attachEvent("onchange",f); }
crmField.ReLabel = function(txt){ crmField.Label.innerHTML = txt; }
}

//Test - contact form
var firstname;
function OnCrmPageLoad()
{
firstname = new CrmField("firstname");
firstname.ReLabel("Given Name");
firstname.OnChange( OnFirstnameChange )
}

function OnFirstnameChange()
{
firstname.Alert();
}

OnCrmPageLoad();


Feel free to comment.

isv.config Toggle Toolbar button


Isv.config toolbar buttons don’t support toggling, although you can accomplish this by creating a drop menu sometimes a button is the better choice.Here a simple example that demonstrates how to implement a toggle button.





Isv.config toggle button xml:

<Button Icon="/_imgs/ico_18_role_g.gif" JavaScript="OnDoSomethingClick();">
<Titles>
<Title Text="On" LCID="1033"/>
</Titles>
</Button>


In the entity onload event expose the OnDoSomethingClick function to the page level e.g. this.OnDoSomethingClick = OnDoSomethingClick;

inside the button , before your implementation add the following script:


function OnDoSomethingClick(){
if(OnToolbarButtonClick())
{
//Your Implementation Here...
}
else
{
//Your Implementation Here...
}
}

function OnToolbarButtonClick()
{
//Get the current active HTML Element
var button = document.activeElement;
//Search the LI ( menuitem container ) Element
while( button.tagName != 'LI' ) button = button.parentElement;
/*
Toolbar Image - you need to remove all references to this object
if the button does not contain an image.
*/
var btnImg = button.childNodes[0].childNodes[0].childNodes[0];
//Button Text
var btnTxt = button.childNodes[0].childNodes[0].childNodes[1];
//Saves the state ( direction ) on the button as a toggle attribute
button.toggle = !((button.toggle == 'undefined')? false:button.toggle);
if( button.toggle )
{
// Replace with relevant Off text
btnTxt.innerText = 'Off';
btnImg.src = '/_imgs/ico_18_role_x.gif';
}
else
{
// Replace with original text and image
btnTxt.innerText = 'On';
btnImg.src = '/_imgs/ico_18_role_g.gif';
}
return button.toggle;
}

this.OnDoSomethingClick = OnDoSomethingClick;


If you need to keep the button state between loads you can create a bit attribute and save its value each time a user clicks on the button. Then, in the onload event, assign the bit value to the button Toggle attribute. For example:



var button = getButtonByIdOrByName(); /*Not Implemented*/
//Search the LI ( menuitem container ) Element
while( button.tagName != 'LI' ) button = button.parentElement;

var toggleState = crmForm.all.<bit attribute id>.DataValue
button.Toggle = toggleState!=null?toggleState:false;

Saturday, July 26, 2008

Changing the Activity / History default view

The associated activity and history views within a given entity are not customizable and you cannot change their default view settings.
Although this type of DOM manipulation is unsupported, if this is a “must have” requirement you can implement the change with the following js script.

put the code inside the entity onload event.


//Activity scheduledend options
var ActivityOptions =
{
All : "All",
Overdue :"Overdue",
Today :"Today",
Tomorrow :"Tomorrow",
Next7Days :"NextXDays;7",
Next30Days :"NextXDays;30",
Next90Days :"NextXDays;90",
Next6Months :"NextXMonths;6"
}

//Activity History actualend options
var HistoryOptions =
{
All : "All",
Today : "Today",
Yesterday : "Yesterday",
Last7Days : "LastXDays;7",
Last30Days : "LastXDays;30",
Last90Days : "LastXDays;90",
Last6Months : "LastXMonths;6",
Last12Months: "LastXMonths;12"
}

var _loadarea = loadArea;
loadArea = function(sArea, sParams, sUrl, bIsvMode)
{
//load the iframe
_loadarea(sArea, sParams, sUrl, bIsvMode);

if( sArea != "areaActivityHistory" &&
sArea != "areaActivities" ) return;

//create the iframe object
var iframe = document.getElementById(sArea + "Frame");
//wait until the iframe is fully loaded ("complete")
iframe.onreadystatechange = function()
{
if( iframe.readyState == "complete")
{
var picklist,option;
//reference to the iframe document
var iframeDoc = iframe.contentWindow.document;
switch(sArea)
{
case "areaActivityHistory":
picklist = iframeDoc.all.actualend[0];
/* change to suit your needs */
option = HistoryOptions.Last90Days;
break;
case "areaActivities":
picklist = iframeDoc.all.scheduledend[0];
/* change to suit your needs */
option = ActivityOptions.Next7Days;
break;
default: return;
}
picklist.value = option;
picklist.FireOnChange();
}
}
}