Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

ScriptArguments: An Easy Way to Programmatically Pass Arguments to Script from Codebehind

4.00/5 (1 vote)
16 Jan 2012CPOL2 min read 20.9K  
Pass JavaScript arguments from codebehind to script the easy way!

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:

JavaScript
function fnAddressChange(ddId, labelId, checkId, sameAsId, 
    hidSelectId, hidSameAsId, onSelectEvent)

And in the codebehind, I had this:

C#
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:

C#
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:

C#
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:

JavaScript
function fnAddressIsReadOnly(args) {
     alert(args.ddId);
     alert(args.labelId);
}

Will alert me with:

C#
"ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__DropDownAddress" and 
"ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__LabelAddress".

The great thing is how simple this was to implement:

C#
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.


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)