Home | Blog | Screencasts | Projects
# Wednesday, September 10, 2008

I've posted a couple of articles on JQuery and it's use in SharePoint and also provided some sample web parts. Recently I was putting together these web parts into a single project and I ran into a problem. Each web part was adding the JQuery script resources to the page as if it was the only control on the page, for example the ImageCarousel and the Tag Suggestion web parts both had code that needed to be run on the JQuery load event, this problem would also crop up when multiple instances of the same web part were added to the page. What was outputted to the page was something like:

 

$(document).ready(function(){ 
//function call for webpart1
}
$(document).ready(function(){ 
//function call for webpart2
}
$(document).ready(function(){ 
//function call for webpart2 instance 2
}
 

So I started developing a Script Manager control that I could add to the page that would output the JQuery load event just once, but with all the calls for the page inside this event. As with anything programming related these days, I found what I was looking for at http://codeplex.com/JQueryScriptManager/ I've changed a bit of the implementation, but the basic intent has remained the same. Hopefully I'll be able to get these changes updated to codeplex.

 

Looking at the revised code for the ImageCarousel web part:

 

jQueryManager jqueryManager = null;

protected override void OnInit(EventArgs e)
{
    
    jqueryManager = jQueryManager.GetCurrent(Page);
    if (jqueryManager == null)
    {
        jqueryManager = new jQueryManager();
        Page.Controls.Add(jqueryManager);
    }
    Page.ClientScript.RegisterClientScriptInclude("JCarousel", Page.ClientScript.GetWebResourceUrl(this.GetType(), 
        "JQueryWebParts.js.jquery.jcarousel.pack.js"));
    base.OnLoad(e);
}
 
 

Now inside the PageInit we check for the presence of a JQueryManager script control, if we don't find one, we add it to the controls collection. Just like the ASP.NET Ajax ScriptManager control, there can only be one per page.

 

Now to add code that is globally scoped which also resides in the same script block where our OnLoad event lives:

 

jqueryManager.RegisterScript("-- javascript code without <script> blocks");
//example:
jqueryManager.RegisterScript("var someItems = [5,4,3]");
            
 

To get javascript to run when the page is loaded (this will bundle calls into a single load event):

 

jqueryManager.ReadyFunctions.Add(new RegisterStartFunction("jQuery('#carousel').jcarousel();"));

Use the ReadyFunctions collection which takes a RegisterStartFunction object as a parameter.

 

Internally the JQuery script manager control is performing the following:

 

StringBuilder Start = new StringBuilder();

if (Scripts != null)
{
    foreach (RegisterScriptBlock r in Scripts)
        Start.Append(r.ScriptBlock + Environment.NewLine);
}

if (ReadyFunctions != null)
{
    Start.Append("$(document).ready(function(){");

    foreach (RegisterStartFunction r in ReadyFunctions)
        Start.Append(r.FunctionName + Environment.NewLine);

    Start.Append("});\n\n");
}

Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "JQuery", Start.ToString(), true);

 

The source code can be downloaded here. This includes the updated JQuery Script Manager and the ImageCarousel web part that I've previously posted about.

 

I think this approach will provide a nice platform to continue building web parts based on JQuery Plugins, have fun.

Statistics
Total Posts: 191
This Year: 0
This Month: 0
This Week: 0
Comments: 41