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.
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.
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.
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");
}
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.
Related
i want to dynamically add route to script src on an html page.
for example,
<script src="../../../library/vendor/jquery/jquery-3.1.1.min.js"></script>
when i use web server and load this code, not working. maybe it should put web server url prefix. so i want to change below.
<script src="mySite/../../../library/vendor/jquery/jquery-3.1.1.min.js"></script>
or,
other things that root-relative path set?
This cannot be achieved by html or javascript only. You need at least a framework which is able to "render" your html before it is send to your browser and replace "mySite".
Example in JSF 2.x it would look like this:
<link href="#{request.contextPath}/css/style.css" rel="stylesheet" type="text/css"/>
Or Thymeleaf:
<a th:href="#{/order/list}">
If you want to develop for example a one page site, where the content is replaced dynamically by ajax, then you need at least one page which is dynamically created by one of this frameworks.
Use below JavaScript code:
var scr = document.createElement('script');
var myurl = 'http://example.com/myjavascript.js'
scr.setAttribute('src',myurl);
document.head.appendChild(scr);
or you can create a function like this:
function addMyScript(url) {
var scr = document.createElement('script');
scr.setAttribute('src', url);
document.head.appendChild(src);
}
you can dynamically decide your url and call the function by passing it as a parameter:
addMyScript('http://example.com/myjavascript.js');
I'd like to have a Play template that is a JS file (as opposed to having <script> tags inside an HTML template). The reason for this is so that the script can be cached. However, I need to create a differences in the script depending on where it's included and hoped to do this with Play's template system. I can already do so if I use embedded scripts, but those can't be cached.
I found an existing question that also asks the same thing, but the answer is totally different (different goals).
That's easy, just... create view with .js extension, i.e.: views/myDynamicScript.scala.js:
#(message: String)
alert('#message');
//Rest of your javascript...
So you can render it with Scala action as:
def myDynamicScript = Action {
Ok(views.js.myDynamicScript.render(Hello Scala!")).as("text/javascript utf-8")
}
or with Java action:
public static Result myDynamicScript() {
return ok(views.js.myDynamicScript.render("Hello Java!"));
}
Create the route to you action (probably you'll want to add some params to it):
GET /my-dynamic-script.js controllers.Application.myDynamicScript()
So you can include it in HTML templite, just like:
<script type='text/javascript' src='#routes.Application.myDynamicScript()'></script>
Optionally:
You can also render the script into your HTML doc, ie by placing this in your <head>...</head> section:
<script type='text/javascript'>
#Html(views.js.myDynamicScript.render("Find me in the head section of HTML doc!").toString())
</script>
Edit: #See also samples for other templates types
I am developing a simple pyramid application where I am using JQuery to do AJAX requests. I have until now had my javascript code within my chameleon templates. Now I want to extract my javascript into another location (e.g. as static resources).
My problem is that I find my javascript code relies on dynamically generated content like so:
$.post("${request.route_url('my_view')}",{'data': 'some data'}, function(html){
$("#destination").html(html);
});
The dynamic element being:
"${request.route_url('my_view')}"
Which is calling the route_url method of the request object within the template.
Is there a recognised pattern for separating such javascript files into their own templates and providing routes and views for them or do I simply keep my javascript in my page template?
Yes; you generally put context-specific information like expanded routes into the templates and access this information from your (static) JavaScript libraries.
Including the context info can be done in various ways, depending on taste:
You could use a data attribute on a tag in your generated HTML:
<body data-viewurl="http://www.example.com/route/to/view">
...
</body>
which you then, in your static JS code load with the jQuery .data() function:
var viewurl = $('body').data('viewurl');
Use a made-up LINK tag relationship to include links in the document head:
<head>
<link rel="ajax-datasource" id="viewurl"
href="http://www.example.com/route/to/view" />
...
</head>
which can be retrieved using $('link#viewurl').attr('href'), or $('link[rel=ajax-datasource]').attr('href'). This only really works for URL information.
Generate JS variables straight in your template, to be referenced from your static code:
<head>
...
<script type="text/javascript">
window.contextVariables = {
viewurl = "http://www.example.com/route/to/view",
...
};
</script>
</head>
and these variables are referable directly with contextVariables.viewurl.
I have in my application layout file an external javascript file witch has several lines of code and at the end runs a function like BooManager.init() no big deal...
the problem is, it is not running the inside code on this javascript file.
this is how i use it:
<script type="text/javascript">
bb_bid = "1615455";
bb_lang = "en-US";
bb_keywords = "iphone4s, apple";
bb_name = "custom";
bb_limit = "8";
bb_format = "bbb";
</script>
<%= javascript_include_tag "http://widgets.boo-box.com/javascripts/embed.js" %>
but it didn`t do anything it was suposed to do...
i`ve tried in simple html file and it works... what am i doing wrong?
NOTE:
the default way in html is this:
<script type="text/javascript">
bb_bid = "1615455";
bb_lang = "en-US";
bb_keywords = "keywords, between, commas";
bb_name = "custom";
bb_limit = "8";
bb_format = "bbb";
</script>
<script type="text/javascript" src="http://static.boo-box.com/javascripts/embed.js"></script>
-- EDIT --
the result generated by rails:
<script type="text/javascript" src="http://static.boo-box.com/javascripts/embed.js"></script>
It's not evaluating the script when loading using the <%= method. I'm not familiar with that syntax, but from the effect, that's what it sounds like. It's treating the script as html rather than code.
jQuery has a script load function that will get a script dynamically from a URL and then eval() it to execute it.
UPDATED WITH SAMPLE CODE
Add jQuery to your app:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
Then use it to load your script:
$.getScript('http://widgets.boo-box.com/javascripts/embed.js');
UPDATE NUMBER 2
I was able to duplicate the problem in this fiddle: http://jsfiddle.net/7x2zT/4/
If what you are trying to accomplish is to get your parameters activated before the script shows the widget - the default one looks like a sidebar, whereas your parameters make it more of a banner, then just make sure you put your parameters above the <script src stuff.
If you must be able to load dynamically, then you're going to have to figure out where the bug lies in the embed code, or if there's some other activation method. That site's documentation doesn't seem to be in English, so I can't help with that.
I've an ASP.NET MVC application with inline JavaScript that only applies to specific views.
If I put all the JavaScript on main Layout page, I get error message as not ID exists on all pages.
Is there a way to externalize the JavaScript for each view?
Here is one way. This is using razor view engine
In you layout page between the head tags create a section
<head>
#RenderSection("Head", required: false);
</head>
then in your view create a section and put your script tags in it.
#section Head
{
<script type="text/javascript">
do some java script...
</script>
}
You could also reference external libraries that are specific to that page, like a light box or something.
If you are using MVC 2 you can use a content placeholder.
// this goes in your master page in your head tag
<asp:ContentPlaceHolder id="Script" runat="server"/>
// this goes in your view -- not partial
<asp:Content ID="Content1" ContentPlaceHolderID="script" runat="server">
<script type="text/javascript" src="foo.js"></script>
</asp:Content>
In MVC 3 you can do this.
I use a HtmlHelper extension to register my used scripts on each controller-action and the "MasterPage" renders each registered script with the correct script tag.
HtmlHelper:
public static void RegisterScript(string path)
{
if (!HttpContext.Current.Items.Contains("RegisteredScripts"))
HttpContext.Current.Items.Add("RegisteredScripts", ";" + path);
else
HttpContext.Current.Items["RegisteredScripts"] = ";" + path;
}
public static MvcHtmlString RegisteredScripts(this HtmlHelper html)
{
var lines = new StringBuilder();
if (html.ViewContext.HttpContext.Items.Contains("RegisteredScripts"))
{
foreach (var k in html.ViewContext.HttpContext.Items["RegisteredScripts"].ToString().Substring(1).Split(';'))
{
lines.Append(html.Script(k));
}
}
return MvcHtmlString.Create(lines.ToString());
}
// Helper-functions
public static MvcHtmlString Script(this HtmlHelper html, string path)
{
if (!ExistsInContext(html, path))
{
return Render(html, "<script type=\"text/javascript\" src=\"{0}\"></script>", path);
}
return MvcHtmlString.Create("");
}
private static bool ExistsInContext(HtmlHelper html, string path)
{
return html.ViewContext.HttpContext.Items.Contains(path);
}
In the controller-action just call:
Helpers.HtmlHelpers.RegisterScript("~/Scripts/custom.js");
Hope this helps
The javascript could test if 'ID' is null or undefined, and not fire the code if it is.