24

ASP.NET allows to generate HTML dynamically using server tags (razor or ASPX). But Is there any good way to generate *.js or *.css content the same way, other than using inline(embedded) CSS/Javascript. Nowadays with technologies like Ajax more and more logic moves from server-side to client side in Javascript. It would be great to have that opportunity to generate JS dynamically using all flexibility that ASP.NET provides for HTML generation.

For example, my Javascript contains Knockout view model declaration with initial data loaded from server during Javascript rendering, and some additional js-functions, so in my Html instead of embedded scripts I want to have script references like that:

<script src="~/Scripts/ContactViewModel.js?contactId=@Model.ContactId"></script>

Another example, where developer might need it is using user-profile based CSS. User profile information contains style information (fonts, colors, not just theme) that must be respected during CSS generation, so In my view I will have something like:

<link href="~/Styles/CurrentUserOverrides.css" rel="stylesheet" />

CurrentUserOverrides.css will be generated dynamically based on profile data of authenticated user.

How to do that using ASP.NET MVC? I want to find solution that will allow me to do this as easy as I create dynamic HTML using ASP.NET, with properly working intellisence and everything else what VS offers for ASP.NET views.

Philipp Munin
  • 5,610
  • 7
  • 37
  • 60
  • I'm not sure I understand the benefit of what you are trying to accomplish. Why would you want to generate Javascript that was context sensitive for a particular page? – Erik Philips Apr 18 '13 at 20:32
  • Are you trying to consume the contactId within ContactViewModel.js (and ContactId of 123 is actually rendered by your view model)? – FiveTools Apr 18 '13 at 20:38
  • Yes, ContactViewModel.js needs to declare object with field values loaded from database by specified ContactId – Philipp Munin Apr 18 '13 at 20:43

4 Answers4

17

The best solution so far I found for that is the following:

Dynamic Javascript and CSS in ASP.NET MVC using Razor Views

You just create views: CurrentUserOverrides.css.cshtml, ContactViewModel.js.cshtml. This views will contain single HTML block (<script> or <style>), so IntelliSense works fine. Then you create controller that renders that view, trims the root tag and return content with appropriate content type.

sritmak
  • 989
  • 9
  • 18
Philipp Munin
  • 5,610
  • 7
  • 37
  • 60
9

Dynamic CSS in a CSHTML File

I use CSS comments /* */ to comment out a new <style> tag and then I return; before the closing style tag:

/*<style type="text/css">/* */

    CSS GOES HERE

@{return;}</style>

Dynamic JS in a CSHTML File

I use JavaScript comments <!--// to comment out a new <script> tag and then I return; before the closing script tag:

//<script type="text/javascript">

    JAVASCRIPT GOES HERE

@{return;}</script>

MyDynamicCss.cshtml

@{
var fieldList = new List<string>();
fieldList.Add("field1");
fieldList.Add("field2");

}/*<style type="text/css">/* */

@foreach (var field in fieldList) {<text>

input[name="@field"]
, select[name="@field"]
{
    background-color: #bbb;
    color: #6f6f6f;
}

</text>}

@{return;}</style>

MyDynamicJavsScript.cshtml

@{
var fieldList = new List<string>();
fieldList.Add("field1");
fieldList.Add("field2");
fieldArray = string.Join(",", fieldList);

}

//<script type="text/javascript">

$(document).ready(function () {
    var fieldList = "@Html.Raw(fieldArray)";
    var fieldArray = fieldList.split(',');
    var arrayLength = fieldArray.length;
    var selector = '';
    for (var i = 0; i < arrayLength; i++) {
        var field = fieldArray[i];
        selector += (selector == '' ? '' : ',')
                    + 'input[name="' + field + '"]'
                  + ',select[name="' + field + '"]';            
    }
    $(selector).attr('disabled', 'disabled');
    $(selector).addClass('disabled');
});
@{return;}</script>

No Controller Required (using Views/Shared)

I put both of my dynamic scripts into Views/Shared/ and I can easily embed them into any existing page (or in _Layout.cshtml) using the following code:

<style type="text/css">@Html.Partial("MyDynamicCss")</style>
<script type="text/javascript">@Html.Partial("MyDynamicJavaScript")</script>

Using a Controller (optional)

If you prefer you may create a controller e.g.

<link rel="stylesheet" type="text/css" href="@Url.Action("MyDynamicCss", "MyDynamicCode")">
<script type="text/javascript" src="@Url.Action("MyDynamicJavaScript", "MyDynamicCode")"></script>

Here's what the controller might look like

MyDynamicCodeController.cs (optional)

[HttpGet]
public ActionResult MyDynamicCss()
{
    Response.ContentType = "text/css";
    return View();
}

[HttpGet]
public ActionResult MyDynamicJavaScript()
{
    Response.ContentType = "application/javascript";
    return View();
}

Notes

  • The controller version is not tested. I just typed that off the top of my head.
  • After re-reading my answer, it occurs to me it might be just as easy to comment out the closing tags rather than use the cshtml @{return;}, but I haven't tried it. I imagine it's a matter of preference.
  • Concerning my entire answer, if you find any syntax errors or improvements please let me know.
Jonathan
  • 949
  • 1
  • 11
  • 13
  • What a great answer. Thank you. Exactly what i've needed. I jsut didnt understand the tricky `//` part. can you elaborate ? – Royi Namir Dec 25 '18 at 11:22
  • 1
    @RoyiNamir **Autocomplete** and colors. In the JavaScript example, the web browser is reading JavaScript, sees `//` and ignores the rest of the line as a JavaScript comment. So web browsers ignore the ` – Jonathan Dec 26 '18 at 13:24
  • 1
    BTW - I've managed to do it without "return " part etc : https://i.imgur.com/yxp52fL.jpg . So I don't understand now the `@{return;}` part – Royi Namir Dec 26 '18 at 13:28
  • Nothing after `@{return;}` will be sent to the browser. cshtml execution ends there. `@{` begins inline C# within a cshtml view. `return;` usually returns from a method or function, but in this case it returns from the cshtml page. `}` ends the inline C# within the cshtml page. – Jonathan Mar 02 '19 at 12:32
4

It's too late but still interesting subject, here is my solution: form your cshtml call like that:

<script src='@Url.Action("GetJS", "Home")'></script>

Create a controller method that generate the JS or CSS like that :

public ActionResult GetJS()
{
     byte[] jsDATA = System.Text.ASCIIEncoding.ASCII.GetBytes(mystingJS); 
     return File(jsDATA, "text/javascript");
}
Mohamed SAIM
  • 69
  • 1
  • 7
-2

There is a relatively new language TypeScript that I think might be what you are looking for with JavaScript, not for CSS though. Here is a post for getting that working in ASP.NET MVC4.

Nathan
  • 1,016
  • 7
  • 16
  • Yeah, unfortunately TypeScript is out of box solution and it's also not clear how IntelliSense works there. – Philipp Munin Apr 20 '13 at 22:30
  • 1
    At the time of writing this, TypeScript is starting to mature and the intellisense in VS is excellent. Although, I'm not sure this really is what the user is asking for. – Alex Dec 06 '14 at 16:48