Richard
Richard

Reputation: 4415

ASP.NET Webforms, JavaScript in user controls

We are struggling a little regarding the right implementation of JavaScript in our solution (APS.NET Webforms).

We want to have all (or at least as much as possible) of our javascript at the bottom of pages, according to best practice, so pages load HTML and CSS first and give a better user experience.

There is a lot of jQuery code throughout our project that is often specific to certain controls, so we don't want that to load on every page.

Currently jQuery itself, including jQuery UI are positioned at the top of pages, so that we can have jQuery usages in controls (either from js files or sometimes inline code), however, we want to move all that stuff down to the bottom of the page. We have already added a contentplaceholder ("JavascriptFooter") at the bottom of the page, so we can place javascript from pages in the footer of the page, but we're stuck on the controls.

What are best practices for this? Should we externalize all JS and in the JS check if a control is loaded? But then we will be showing too much stuff all the time. Or is there another way?

Upvotes: 6

Views: 4512

Answers (3)

ctorx
ctorx

Reputation: 6931

Firstly, the best approach is to externalize the JavaScript from controls in a JS file that is loaded on the first request to your site and all subsequent requests (i.e. site.js). This file will then be cached by the browser and users won't have to download the JS over and over again as they would if the JS stays in the controls.

Next, you need to create a mechanism to only execute the portions of script that are relevant to the executing page or control.

There are several ways you can achieve this, however if I was in your situation I would do it this way.

Identify a page level element that wraps most of your content ... typically people call this wrapper. Dynamically add a custom attribute to wrapper called "data-js". Set the value of "data-js" dynamically (on the server side) from either a page or a user/custom control. Allow it to have multiple keys delimited by a pipe (|) or other character.

<div class="wrapper" data-js="funtion1|function2">
     <!-- Page content goes here -->
</div>

Leverage jQuery to look for this attribute on DOM ready, and execute custom JS functions based on the value in data-js attribute. That function will contain only code that is relevant for the current page or controls.

 $(function(){
    var funcKeys = $('.wrapper').attr('data-js');
    if(funcKeys != null)
    {
        var funcs = funcKeys.split('|');
        for(var i=0; i< funcs.length; i++) {
           var funcName = eval(funcs[i]);
           if(typeof funcName == 'function') {
                funcName();
           }
        }
    }    
});

Using this approach you only need the jQuery CDN reference, a reference to your site's JS file and the above snippet of code in your layout.

Then you need simply include the page/control specific functions in your site specific JS file, like so:

function function1() {
    alert("This is function 1");
}

function function2() {
    alert("This is function 2");
}

I hope this helps.

FYI, I also setup a fiddle for you to play with how it works: http://jsfiddle.net/hh84f/1/

Upvotes: 1

CoderMarkus
CoderMarkus

Reputation: 1118

First, I would suggest loading Jquery from a CDN. Here is the code for Google:

<script type="text/javascript">
    document.write(["\<script type='text/javascript' src='", 
    ("https:" == document.location.protocol) ? "https://" : "http://", 
    "ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'>\<\/script>"].join(''));
</script>

That way, if the visitor has been served this on another site, it will already be cached. In addition, it will download in parallel as it is being delivered from a different host.

I also agree with @ctorx - you should use document ready execution.

In addition, you could use a ScriptManager and create all your control specific JS in the code behind of each control (probably a good idea anyways if that control is the only object utilizing that JS) - all this code renders at the bottom of the page.

Example:

Page pg = (Page)System.Web.HttpContext.Current.Handler; // or this.Page in .ascx
ScriptManager.RegisterStartupScript(pg, typeof(Page), "myJS", "[... your code ]", true);

Upvotes: 4

Rob Allen
Rob Allen

Reputation: 2911

I bet there are as many solutions to this as there are companies using webforms. That said, you can always use the request context to store the necessary scripts and then write them before the page renders.

You could possibly use requireJS as well. I'm no expert, but there are alot of options and it would handle script loading timeouts, circular dependencies, defining multiple dependencies, etc.

Upvotes: 1

Related Questions