cw_dev
cw_dev

Reputation: 465

Change CSS files on the fly

I would like to change the CSS files on the fly (dynamically). I am developing in MVC 4 using Razor views. At the moment they are pulled from the web.config...

My bundle registration

bundles.Add(New StyleBundle("~/Content/themes/" + Domain.GetTheme + "/css").Include(
    "~/Content/themes/" + Domain.GetTheme + "/Main.css",
    "~/Content/themes/" + Domain.GetTheme + "/Content.css"))

Razor View

@Styles.Render("~/Content/themes/" + Domain.GetTheme + "/css")

Code in GetTheme property

Public Shared ReadOnly Property GetTheme As String
    Get
        Return ConfigurationManager.AppSettings("Theme")
    End Get
End Property

I'm not sure if this is the best way, but it works.

Research so far...

But now I want to change the theme on the fly. My initial idea was to access a querystring parameter. So if it contained ?Theme=Green then the CSS files would pick up the green version. The querystring value would be stored in session state so that the CSS would continue to use green until changed again via the querystring.

I started off by creating an attibute that I could apply to my controller...

Attribute

Public Class LoadThemeAttribute
    Inherits ActionFilterAttribute

    Public Overrides Sub OnActionExecuted(filterContext As ActionExecutedContext)
        MyBase.OnActionExecuted(filterContext)

        If HttpContext.Current.Request.QueryString("Theme") IsNot Nothing Then
            HttpContext.Current.Session("Theme") = HttpContext.Current.Request.QueryString("Theme")
        End If

    End Sub
End Class

Controller

<LoadTheme>
Public Class CompanyController
    Inherits System.Web.Mvc.Controller

    ...
End Class

Then in my _Layout.vbhtml razor view I override the CSS files as follows:-

@If Session("Theme") IsNot Nothing Then
    @<link href="/Content/themes/@Session("Theme")/Main.css" rel="stylesheet"/>
    @<link href="/Content/themes/@Session("Theme")/Content.css" rel="stylesheet"/>
Else
    @Styles.Render("~/Content/themes/" + Domain.GetTheme + "/css")
End If

I couldn't use the Render statement, I am assuming this is because this is called once when the project loads and cannot be called again. I certainly could not get it to work.

So my question is this:- Everything seems to work, but I just want to know if this is a good approach - is it a good MVC way to change the CSS files?

Upvotes: 1

Views: 3149

Answers (1)

Exzile
Exzile

Reputation: 397

So I've pretty much had the same issue you had. A quick cure I did was remove my theme/css from the bundle and put it separate on my layout.vbhtml /master page. I gave the tag and id property, referenced it an a javascript function and changed the href to the different css I wanted loaded. If this is not enough information let me know, ill detail more.

Updated example from my program. layout.vbhtml header

<head>
<meta charset="utf-8" />
<title>Amtrust - Print Metrics @*@ViewData("Title")*@</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<meta name="viewport" content="width=device-width" />
<link id="theme"
 href="~/Content/themes/jquery-blue-theme/css/start/jquery-ui-                                    1.10.3.custom.css"                  rel="stylesheet" />
@Styles.Render("~/Content/_Layout")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryui")
@Scripts.Render("~/Scripts/_Layout")
</head>

site.master.js -> js file I use to keep the theme consistent on all pages.

var domainName;
$(document).ready(function () {
//loading = document.getElementById('loading');
//pagediv = document.getElementById('page');
//alarum = document.getElementById('alarum');
//alarum = $('#alarum'); 
      jQuery's .append() method
$("#menu").menu();
hideLoading();
//Apply UI skins to controls
$(function ()

 {
    $('#printinvButton').button();
    $('#docsearchButton').button();
    $('#policysearchButton').button();
    $('#metricsButton').button();
    $('#themeButton').button();
});

//setInterval(function () { bannerAlert() }, 4000);
if (sessionStorage.getItem('theme') != null) {
    $('#theme').attr('href', sessionStorage.getItem('theme'));
}

domainName = location.protocol + '//' + location.host;
});

var counter = 0;
function switchTheme() {
var theme;
var imageRoot = document.body.getAttribute('data-root');
if (counter == 0) {
theme = domainName + '/PrintRoomMetrics/Content/themes/jquery-blackgrey-                          theme/css/blackGrey/jquery-ui-1.10.3.custom.min.css';
    $('#theme').attr('href', theme);
    counter++;
}
else if (counter == 1) {
     theme =
 domainName + '/PrintRoomMetrics/Content/themes/jquery-chrome-theme
/css/overcast/jquery-ui-1.10.3.custom.min.css';
    $('#theme').attr('href', theme);
    counter++;
}
else if (counter == 2) {
    theme = domainName + '/PrintRoomMetrics/Content/themes/jquery-blue-theme/css/start/jquery-ui-    1.10.3.custom.min.css';
    $('#theme').attr('href', theme);
    counter++;
}
if (counter == 3) {
    counter = 0;
}
sessionStorage.setItem('theme', theme);// store data for session
}

hope you can figure out what I did. Ignore my app code and only pay attention to what you need.

Upvotes: 1

Related Questions