views:

583

answers:

3

I am trying to include the js and css in my code behind in my master pages and user controls in Page_Load event.

But apparently, js breaks since Page_Load of user controls loads BEFORE Page_Load of a master page. I include my jquery libs used across the site in my master pages, but scripts used in user control are included in user control only. The thing is that user control js scrips uses jquery functionality (as it should), but when it tried to run, it breaks since jquery libs are not loaded yet. Anwyays, is there a way around this frustrating mess?

I use this to include js in my code behind. relativeResolvedPath is basically ResolveUrl(url)

    HtmlGenericControl js = new HtmlGenericControl("script");
    js.Attributes.Add("type", "text/javascript");
    js.Attributes.Add("src", relativeResolvedPath);
    Page.Header.Controls.Add(js);
+1  A: 

First, Page.Controls.Add will add the script block at random places in your html document. You should really only be adding script files in the header, or at the bottom of the page (searching online will tell you that the bottom of the page is preferred for better UI performance).

In order to ensure proper order of your javascript files, I would look into the ASP.Net AJAX Script Loader and the Script Manager.

The Script Manager will work if you add the scripts in the proper order. Your problem would be better solved using the AJAX Script Loader

Gabriel McAdams
I corrected my code. I use Page.Header.Controls.Add, not Page.Controls.Add. i verified that all the scripts get added to header, so that's not the issue.
gnomixa
I understand the issue. Where the script tags should reside was a side point. In order to solve your problem, I would look into the AJAX Script Loader. A simple solution would be to load the scripts at the bottom of the page for user controls and at the top from your master page.
Gabriel McAdams
A: 

Use Page_Init in your MasterPage to make code run before child page and UserControl Page_Load events.

Don't forget to do the occasional "View Source" as a sanity check. You gotta make sure that stuff goes into the response in the order you expect.

The client script used in your UserControls will not execute until the response is sent to the user agent, so as long as the jQuery libraries are included earlier in the response, you should be ok. This is not actually a lifecycle issue unless you have server code mixed in with the client code that you are sending.

I have this in the head of my MasterPage

    <link rel="shortcut icon" href="<%#ResolveUrl("~/favicon.ico" ) %>" />
    <script type="text/javascript">
        var applicationRoot = "<%# webController.AppUrl %>";
    </script>
    <asp:Literal ID="litJqueryMinified" runat="server" /><asp:PlaceHolder id="phjQuery" runat="server"><script src="Script/jquery-1.3.2.js" type="text/javascript"></script></asp:PlaceHolder>
    <asp:Literal ID="litJqueryUIMinified" runat="server" /><asp:PlaceHolder id="phjQueryUI" runat="server"><script src="Script/jquery-ui-1.7.2.custom.min.js" type="text/javascript"></script></asp:PlaceHolder>
    <script src="<%#ResolveUrl("~/Script/jquery.fancybox-1.2.1.pack.js" ) %>" type="text/javascript"></script>
    <script src="<%#ResolveUrl("~/Script/jquery.maskedinput-1.2.2.min.js" ) %>" type="text/javascript"></script>
    <script src="<%#ResolveUrl("~/Script/jquery.cycle.all.min.js" ) %>" type="text/javascript"></script>

and this in the codebehind:

        // Swap the jQuery inlcude for the minified version
        phjQuery.Visible = false;
        phjQueryUI.Visible = false;
        string jQueryAddress = currentSettings != null && currentSettings["jQueryLocation"] == "local" ? ResolveUrl("Script/jquery-1.3.2.min.js") : "https://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js";
        string jQueryUIAddress = currentSettings != null && currentSettings["jQueryLocation"] == "local" ? ResolveUrl("Script/jquery-ui-1.7.2.custom.min.js") : "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js";
        litJqueryMinified.Text = "<script src=\"" + jQueryAddress + "\" type=\"text/javascript\"></script>";
        litJqueryUIMinified.Text = "<script src=\"" + jQueryUIAddress + "\" type=\"text/javascript\"></script>";

This allows me to have it minified or hosted by google in production, but use the full version in dev, with intellisense.

Don't forget this in your Page_Load to get ResolveUrl to work:

            Page.Header.DataBind();

Hope this helps. :)

Chris
thanks! i traced the order at which the init and load events get executed and surely enough your solution worked!
gnomixa
Awesome. And note that pages even have a PreInit, but master pages do not.
Chris
+1  A: 

Use a ScriptManager. It's very easy:

<asp:ScriptManager ID="SM1" runat="server">
  <Scripts>
    <asp:ScriptReference Name="Script.js" />
  </Scripts>
</asp:ScriptManager>

To make it even easier, you just add an empty script manager control to your masterpage:

<asp:ScriptManager ID="MasterPageScriptManager" runat="server" />

And a script manager proxy on all your pages/controls which will have custom scripts loaded:

<asp:ScriptManagerProxy  ID="SM1" runat="server">
  <Scripts>
    <asp:ScriptReference Name="Script.js" />
  </Scripts>
</asp:ScriptManagerProxy>

Edit: if this isn't what you're looking for, I apologize. It sounds like you're just trying to work out the proper location of your scripts. Another thing you can do if this is the case is to include jQuery in your masterpage and any future scripts as:

<script type="text/javascript" src='<%= ResolveUrl("~/js/script.js") %>'></script>

I would recommend not loading javascript from the codebehind unless you're either dynamically building the javascript code, or you're building the application and releasing it to someone to tweak the UI and you don't want that functionality tampered with.

If you're loading alerts or something similar, use something like:

string myScript = "$(document).ready(function() { alert('message');});";
Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "alerting", myScript, true); 
Jim Schubert
so I can't have JS being injected into head from code behind inside ascx file? Essentially, what I was trying to have is a user control that's self contained - as in - I don't need to include any js on the pages that use the user control - I wanted it to come as a ready-to-use with all the css and js loaded into it automatically. I can, of course, just include the scripts for user control inside a master page but that just seems wrong. They don't need to be included there - they only need to be included where user control is used. This is very frustrating - not sure what .net creators were on.
gnomixa
i will try your solution when I get to work tomorrow, thanks!
gnomixa