views:

108

answers:

5

I have a partial view (.ascx) that should include its own CSS file as it's used in multiple other views. How do I inject a stylesheet in the page server-side, i.e. without using JavaScript?

A: 

why not put the link tag in your partial view

<link rel="stylesheet" href="yourstyle.css" type="text/css" />

ajay_whiz
That renders the document invalid.
Dario Solera
I guess the html validators are making it invalid. But I am sure the browsers are rendering properly. I don't see in specs where they tell you that it can only be inside `head` tag
ajay_whiz
+1  A: 

Dario - due to using this for partialviews, you're going to always have the problem that the <head> section of the document is already in place and therefore can't be modified. If you want to remain WC3 compliant, then you'll have to put any further css into the head section via javascript. This may or may not be desirable (if you've got to cater for downsteam browsers with javascript turned off).

the main problem that you may be aluding to is the fact that you can't put <asp:contentplaceholders> into your partials. this is a pain (tho understandable as the masterpage ref would tie the partial too closely to a particular master page).

To this end, I've created a little helper method that does the basic grunt work to put the css file into the head section automatically.

edit - (as per Omu's js suggestion) this is a nice little halfway house:

// standard method - renders as defined in as(cp)x file
public static string Css(this HtmlHelper html, string path)
{
    return html.Css(path, false);
}
// override - to allow javascript to put css in head
public static string 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 "";

    // 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 sb.ToString();
}

usage:

<%=Html.Css("~/Content/yourstyle.Css")%>

or:

<%=Html.Css("~/Content/yourstyle.Css", true)%> // or false if you want!!

worth a back-pocket approach if all else fails. it may also be possible to adapt the logic above to hit an actionfilter and add the css to the reponse headers etc.., rather than outputting the js string.

jim
btw -i found this article that adds some code to allow you to do this: http://somewebguy.wordpress.com/2010/04/06/adding-stylesheets-scripts-in-asp-net-mvc2/ then follow the links to http://gist.github.com/358458
jim
A: 

why not use jQuery

$(function(){
$("head").prepend("<link rel='stylesheet' href='yourstyle.css' type='text/css' />");
});
Omu
Omu - this would be a good approach. however, the OP requested a server side (without javascript) solution!!
jim
that said, it might be possible to adapt this as a helper method that worked along similar lines to mine below, except that it created the little jQuery method to be added to the page. shame really that the js solution isn't viable as this would combine server and clientside approach.
jim
+1  A: 

Is there a reason you cannot just put the stylesheet in the main view page? Unless it is extremely large, it should not cause your page to load significantly slower when not being used, especially after compression.

Furthermore, if the partial view is being retrieved by ajax, you will end up re-downloading the css file multiple times (depending on the browser's caching).

KallDrexx
I'd like my partial view to be self-contained (besides, it's rendered server-side, not loaded via AJAX).
Dario Solera
+1  A: 

I'm not an ASP.NET or MVC expert, but I am currently working on a project with it. Would it be possible to include something like this in the head of your master page?

<asp:ContentPlaceHolder ID="HeadContent" runat="server"></asp:ContentPlaceHolder>

Then somehow get your CSS into the content placeholder?

<asp:Content ID="styleSheetHolder" ContentPlaceHolderID="HeadContent" runat="server">
  <link rel='stylesheet' href='yourstyle.css' type='text/css' />
</asp:Content>

It looks like you'd have to do this from the calling page, which would introduce duplication of code. I'm not sure how to get around that. Maybe it could it be done with an HTML helper.

coderj
You would have to knowingly do this outside of the partial (ie. in the page). It'd be great if there was a solution that worked from within partials for cases that they're conditionally included.
Drew Noakes