0

Looking for an elegant way of having scripts added once on a page and that's it.
I have a partial view that requires 2 CSS files and 2 JS files. In most places, there is only need for 1 of the partial views. On a single page though, I need 3 of these same partial views, and each partial view has the 4 files, so I have 6 JS links and 6 CSS links. Quite ugly.

I original idea was to use jQuery to see if the tags (by id) are existant on the page yet or not. If they aren't, then add them in. Otherwise, do nothing. This was going to be an inline script like....

<script type="text/javascript" language="javascript">
     function(){
           var jQueryUICSS = $("#jQueryUICSS");
           if(!jQueryUICSS){
                document.write('link id="jQueryUICSS" href="/Content/smoothness/jquery-ui-1.8.5.custom.css" rel="stylesheet" type="text/css" />')
           }
           ...And so on for the other 3 tags.
 };

But, I'm not sure that will work (or will the lead dev accept it):P

Any other ideas?

2 Answers 2

3

David,

I use a couple of static htmlhelpers in my code for exactly this scenario. it works on the principle that the context.items collection gets populated per request and therefore if an item exists in the context.items collection then it doesn't get added twice. anyway, enough of the scottish words of wisdOOOm, 'yill jist be waantin the coade'...

for our Scripts:

public static MvcHtmlString Script(this HtmlHelper html, string path)
{
    var filePath = VirtualPathUtility.ToAbsolute(path);
    HttpContextBase context = html.ViewContext.HttpContext;
    // don't add the file if it's already there
    if (context.Items.Contains(filePath))
        return MvcHtmlString.Create("");

    // add the beast...
    context.Items.Add(filePath, filePath);

    return MvcHtmlString.Create(
        string.Format("<script type=\"text/javascript\" src=\"{0}\"></script>", filePath));
}

for our cuddly css:

// standard method - renders as defined in as(cp)x file
public static MvcHtmlString Css(this HtmlHelper html, string path)
{
    return html.Css(path, false);
}
// override - to allow javascript to put css in head
public static MvcHtmlString Css(this HtmlHelper html, 
                                string path, 
                                bool renderAsAjax)
{
    var filePath = VirtualPathUtility.ToAbsolute(path);

    HttpContextBase context = html.ViewContext.HttpContext;
    // don't add the file if it's already there
    if (context.Items.Contains(filePath))
        return null;

    // otherwise, add it to the context and put on page
    // this of course only works for items going in via the current
    // request and by this method
    context.Items.Add(filePath, filePath);

    // js and css function strings
    const string jsHead = "<script type='text/javascript'>";
    const string jsFoot = "</script>";
    const string jsFunctionStt = "$(function(){";
    const string jsFunctionEnd = "});";
    string linkText = string.Format("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\"></link>", filePath);
    string jsBody = string.Format("$('head').prepend('{0}');", linkText);

    var sb = new StringBuilder();

    if (renderAsAjax)
    {
        // join it all up now
        sb.Append(jsHead);
        sb.AppendFormat("\r\n\t");
        sb.Append(jsFunctionStt);
        sb.AppendFormat("\r\n\t\t");
        sb.Append(jsBody);
        sb.AppendFormat("\r\n\t");
        sb.Append(jsFunctionEnd);
        sb.AppendFormat("\r\n");
        sb.Append(jsFoot);
    }
    else
    {
        sb.Append(linkText);
    }

    return MvcHtmlString.Create( sb.ToString());
}

usage in both cases:

<%=Html.Css("~/Content/Site.Css")%>
<%=Html.Script("~/Scripts/default.js")%>

have fun...

[edit] - pay particular attn to the comment line:

// this of course only works for items going in via the current
// request and by this method
Sign up to request clarification or add additional context in comments.

Comments

0

Put them in your master. CSS and Javascript files are cached. Load once and don't worry about it.

4 Comments

i thought about this once upon a time but the problem for me was that the miriad of partials that i was using would have polluted the master file irrespective of whether the actual code that used them was utilised. horses for courses i guess. your approach would work very nicely on sites where there wasn't a vast proliferation of partials with alternative css and js tho.
"Polluted?" 12 extra lines in your web.config aren't going to kill you. Combine the multiple files into one if 12 lines of code in your master is "too huge" for you. Unless you need them to be dynamic, meaning the same partial could use two different jquery/css files, ANY other solution is over engineering.
jfar - we'll agree to disagree on the 'ANY other solution' - gosh, :)!! the 'count' of lines that you refer to may or may not be 12 or 24 or whatever. plus, there's always the continual 'revisit' to the master file to keep everything going. this opens up the chance of redundancy etc. in my case (not necessarily the one above) 'pollute' is indeed my term of choice. cats and skin do indeed make for variety in taxidermy.. edit - and yes, perhaps the dynamic nature may be a consideration, tho in the case i make above, not necesarily so. anyway, i'll bid you a good night from wet/windy scotland.
@jim - Revisiting the master is no big deal and redundancy? Well thats really really really really simple to check for. This is just reinventing the wheel. If you have that many files you should probably combine and minify them for performance reasons. I see your solution below. IMHO anytime you generate javascript with C# you lose.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.