Providing data to JavaScript functions from code behind

In my previous post, I talked about JavaScript namespaces and functions.
When using WebForms, it can be difficult to call these functions from the code behind in a nice way.
It usually requires some data to initialize the JavaScript function, for example, providing some html element ids as trigger elements.
The Ids of html elements are non-predictable (except when using static ids, but this brings in a whole bunch of different problems) and should be provided from the code behind to avoid the ugly <% %> syntax in your markup file.
I see a lot of people making use of a StringBuilder to write out a JavaScript object. This will work of course, but it is not the nicest and best way to do that, because you will lose your strongly typing and intellisense.

I prefer to create a model and use a JavaScript Serializer to create a json object and provide that to a function.


public class SearchManagerOptions
{
    public string Url { get; set; }
}

.Net has its own serializer; JavascriptSerializer. It is a very simple and straight forward serializer and does the trick.


var options = new SearchManagerOptions { Url = "someurlhere" };
var json = new JavaScriptSerializer().Serialize(options);

The result (json) will look like


"{\"Url\":\"SomeUrl\"}"

This is fine for most common cases.

If you want some extra control over the serialization process, the JavaScriptSerializer will not be your friend and I recommend you to switch to the serializer of json.NET. This is a third party library (available on NuGet) which allows you to control the serialization process by decorating your properties with attributes.
For example, when I want to apply to the JavaScript standard of camel casing properties, I can use an attribute to change the output name of the property.


public class SearchManagerOptions
{
    [JsonProperty("url")]
    public string Ur; { get; set }
}

The json.NET seializer is used as follows:


var options = new Models.SearchManagerOptions { Url = "SomeUrl" };
var json = JsonConvert.SerializeObject(options);

This results in:


"{\"url\":\"SomeUrl\"}"

That’s even better, we now apply to the standard!
Just play around with the json.Net library, it is full of nice serialization tricks. For example, ignoring properties for serialization by adding the JsonIgnore attribute to properties.

Now we need to call the JavaScript function and provide this data.
WebForms provides us two methods for injecting scripts; RegisterClientScriptBlock and RegisterStartupScript.
What is the difference? Good question! Both method signatures are the same. The difference lies in the position where the script is injected in the page.
RegisterClientScriptBlock injects the script at the top of the form element (as one of the first children). This means that none of the html elements are rendered yet. Remember that! All your selectors won’t work! Unless you use a document ready event.
RegisterStartupScript injects the script at the bottom of the form element, which means that all html elements are already rendered.
I usually go for RegisterStartupScript, because I think it is a cleaner solution to inject scripts at the end of your page. It is still injected inside the form element, but that is a limitation of WebForms.


var options = new Models.SearchManagerOptions { Url = "SomeUrl" };
var json = JsonConvert.SerializeObject(options);
var script = string.Format("ViCreative.Managers.SearchManager.init({0})", json);

if (Page.ClientScript.IsStartupScriptRegistered("SearchManagerInitialization"))
{
    Page.ClientScript.RegisterStartupScript(GetType(), "SearchManagerInitialization", script, true);
}

I do not want this script to be injected more than once, which is why I check if this script is already registered. I usually would add “SearchManagerInitialization” to a constant, but for clarity of this blog post, I just added it to the script.

The following two tabs change content below.
I'm a software developer from Utrecht. Interested in DDD, continuous delivery, new technologies & frameworks.

Latest posts by Vincent Keizer (see all)

Leave a Reply

Your email address will not be published. Required fields are marked *