During my on-going adventures AJAXifying a crusty old business app, I have been using a methodology by which most client events are setup in codebehind. The reason for this is I have easy access to my client ids, variables, and resources in codebehind. By constructing the script
function calls at this stage, I can avoid messy and fragile in-line code. What I am endeavouring to do is remove all script from the markup itself. So instead of having MyPage.aspx with script mixed with markup, I have MyPage.js and all functions here. Separate js files avoid fragile in-line code which only fails at runtime, can’t be refactored, and doesn’t play as nice with the debugger. Besides, separation of markup and script is good!
The downside to setting up all this script in the codebehind is it didn’t take long for the number of arguments to grow and become unruly. My script
function signature looked like this:
function fnAddressChange(ddId, labelId, checkId, sameAsId,
hidSelectId, hidSameAsId, onSelectEvent)
And in the codebehind, I had this:
string selectArgs = string.Format("'{0}', '{1}', '{2}', '{3}', '{4}', '{5}'",
_DropDownAddress.ClientID, _LabelAddress.ClientID, _RowSameAs.ChildClientID,
(SameAs && _SameAsAddress != null) ? _SameAsAddress.LabelControl.ClientID :
"-1", _HiddenSelectedID.ClientID, _HiddenSameAs.ClientID);
string selectScript = string.Format("fnAddressSelect({0}); ", selectArgs);
string changeScript = string.Format("fnAddressChange({0}, '{1}'); ",
selectArgs, OnClientSelect);
We can see selectArgs
is getting out of control. Not only is it getting ridiculous to add more to it, the function signature in script is getting huge and the ordering is easier to mess up. So I came up with this solution:
ScriptArguments args = new ScriptArguments ();
args.Add("ddId", _DropDownAddress.ClientID);
args.Add("labelId", _LabelAddress.ClientID);
args.Add("checkId", _RowSameAs.ChildClientID);
args.Add("sameAsId", (SameAs && _SameAsAddress != null) ?
_SameAsAddress.LabelControl.ClientID : "-1");
args.Add("hidSelectId", _HiddenSelectedID.ClientID);
args.Add("hidSameAsId", _HiddenSameAs.ClientID);
Not only is the codebehind cleaner but I don’t have to worry about string.Format
or the order in which I add arguments in. The resulting script generated is:
args.ToString()
"{ ddId : 'ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__DropDownAddress',
labelId : 'ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__LabelAddress',
checkId : 'ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__RowSameAs_
FormField_CheckBox', sameAsId : '-1', hidSelectId : 'ctl00__ContentMain__
ControlOrderSoldTo__AddressSoldTo__HiddenSelectedID', hidSameAsId :
'ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__HiddenSameAs' }"
This is a JavaScript Object with a property per key set to the corresponding value. So in script, I only need to take in one argument, the argument object. I can then access every piece of information inserted into ScriptArguments
via the correct key:
function fnAddressIsReadOnly(args) {
alert(args.ddId);
alert(args.labelId);
}
Will alert me with:
"ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__DropDownAddress" and
"ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__LabelAddress".
The great thing is how simple this was to implement:
public class ScriptArguments : Dictionary<string, string>
{
public override string ToString()
{
StringBuilder script = new StringBuilder("{ ");
this.Keys.ToList().ForEach(key => script.AppendFormat("{0} : '{1}', ",
key, this[key]));
script.Remove(script.Length - 2, 2);
script.Append(" }");
return script.ToString();
}
}
This simple class solves a simple problem. I hope you find it useful.