Externalize JavaScript for Views - javascript

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.

Related

Using RenderSections does not work in asp net

I am new to asp.net. I have to use
#section Scripts{}
but it does not work.
Keep in mind that I adjusted the below code in layout page:
#RenderSection("scripts", required: false)
I read similar posts. But I still couldn't fix my problem.
Is there any other way I can use it?
It should be #section Scripts {} as opposed to #script Scripts{}
section allows you to add something in a view which will be added in the layout.
view
#section scripts {
<script>
alert('hello world');
</script>
}
layout
#RenderSection("scripts", false)
this named section scripts will be rendered wherever specified in layout.
#RenderSection also has 2 signatures:-
public HelperResult RenderSection(string name)
public HelperResult RenderSection(string name, bool required)

How to give dynamic query parameter in <script> src?

I am building a simple asp.net application and in my aspx page I want to reference a script with dynamic query parameter.
For example:
<script src="../javascript/script.js?v=#var#" type="text/javascript"></script>
In the above code script path can have different query parameter in place of #var#.
I have also tried following code to get the parameter value from code behind.
<script src="../javascript/script.js?v=<%# myVar %>" type="text/javascript"></script>
but, here <%# myVar %> returns blank value. If I use = instead of # then it works perfectly if I add the script reference at the bottom of the page.
But, it only works if I reference the script at the bottom of page. otherwise it will throw the error.
"The Controls collection cannot be modified because the control contains code blocks (i.e. `<%= %>`)."
Now, my question is, "Is there any other way to do the same?"
I am assuming you are using ASP.net not MVC. I have tried this with ASP.net and done this by code behind approach you can create your script tag by code behind like below:
protected void Page_Load(object sender, EventArgs e) {
string jScriptValidator;
jScriptValidator = "<script type='text/javascript' src='../javascript/script.js?v=#123'></script>"; // your dynamic script tag with dynamic parameter
Page.RegisterStartupScript("key", jScriptValidator);
}
and result is follows:
Hope it helps you.

A web MVC platform that can dynamically serve js files? [duplicate]

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.

Treeview control in ASP .net

I have a treeview control in my web application. I build this tree view dynamically.
Is there anyway to select a node and change the color of the selected node using javascript or any other method running in client side(i mean without post back).
i am using c# and asp.net to bulid my application
EDIT (To explain a little more on JQuery):
JQuery is a .js file containing JavaScript functions to make it easier to navigate a document, select DOM elements, create animations, handle events, and develop Ajax applications.
You can download JQuery.js file from JQuery official website, then reference to the JQuery.js file (like you reference to other .js file) before you call your first JQuery script, as followed:
<script type="text/javascript" src="jQuery.js"></script>
Or alternatively, you can use the JQuery.js file hosted by Google. This is what I did for my testing. Below is the complete code of my .aspx page:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="TreeView.aspx.cs" Inherits="TreeView" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript"
src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
// You may specify partial version numbers, such as "1" or "1.3",
// with the same result. Doing so will automatically load the
// latest version matching that partial revision pattern
// (e.g. 1.3 would load 1.3.2 today and 1 would load 1.4.2).
google.load("jquery", "1.4.2");
google.setOnLoadCallback(function() {
// Place init code here instead of $(document).ready()
//change cursor to hand when user mouseover tree nodes
$(".TreeView1_0").mouseover(function() {
$(this).css('cursor', 'pointer');
});
//unbold all nodes then bold the selected node to indicate it's selected
$(".TreeView1_0").click(function() {
$(".TreeView1_0").css('font-weight', 'normal');
$(this).css('font-weight', 'bold');
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TreeView ID="TreeView1" runat="server">
</asp:TreeView>
</div>
</form>
</body>
</html>
2 ways I can thought of to implement this:
Wrap your treeview with Ajax UpdatePanel. This is more straight forward.
Remove hyperlink from tree nodes using recursive function, then bind client side click event to all the nodes using JQuery.
More details for method 2 as followed..
Place treeview control onto aspx page
<asp:TreeView ID="TreeView1" runat="server">
</asp:TreeView>
Add dummy nodes and call recursive function to remove hyperlinks
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//add dummy nodes
TreeView1.Nodes.Add(new TreeNode() { Value = "1", Text = "One" });
TreeView1.Nodes.Add(new TreeNode() { Value = "2", Text = "Two" });
TreeView1.Nodes.Add(new TreeNode() { Value = "3", Text = "Three" });
//call recursive function to remove hyperlinks
RemoveHyperLinks(TreeView1, TreeView1.Nodes);
}
}
Implement the recursive function
System.Web.UI.WebControls.TreeView RemoveHyperLinks(System.Web.UI.WebControls.TreeView treeView, TreeNodeCollection treeNodes)
{
foreach (TreeNode node in treeNodes)
{
node.SelectAction = TreeNodeSelectAction.None;//here the link is removed
if (node.ChildNodes != null && node.ChildNodes.Count > 0)
{
treeView = RemoveHyperLinks(treeView, node.ChildNodes);
}
}
return treeView;
}
Place this JQuery code on aspx page
//change cursor to hand when user mouseover tree nodes
$(".TreeView1_0").mouseover(function() {
$(this).css('cursor', 'pointer');
});
//unbold all nodes then bold the selected node to indicate it's selected
$(".TreeView1_0").click(function() {
$(".TreeView1_0").css('font-weight', 'normal');
$(this).css('font-weight', 'bold');
});

Linking JavaScript Libraries in User Controls

I have been using ASP.NET MVC for six months or so and have been checking out the Nerd Dinner example created by those Microsoft guys. One thing I noticed they did when enabling AJAX to RSVP for a dinner, is put the JavaScript references in the User Control being used for RSVPing.
(FILE: RSVPStatus.ascx)
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<NerdDinner.Models.Dinner>" %>
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
This doesn't seem right to me, as there is a really good chance I would be using these same libraries elsewhere, like logon authentication. Plus if I change script versions, I need to hunt down all the references to the libraries.
So I ask if my thinking is correct and these references should actually be in a more central location like the master page?
Please let me know what the best practice is for this and pro's and cons if any.
I would definitely advise against putting them inside partials for exactly the reason you mention. There is a high chance that one view could pull in two partials that both have references to the same js file. You've also got the performance hit of loading js before loading the rest of the html.
I don't know about best practice but I choose to include any common js files inside the masterpage and then define a separate ContentPlaceHolder for some additional js files that are specific to a particular or small number of views.
Here's an example master page - it's pretty self explanatory.
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<head runat="server">
... BLAH ...
<asp:ContentPlaceHolder ID="AdditionalHead" runat="server" />
... BLAH ...
<%= Html.CSSBlock("/styles/site.css") %>
<%= Html.CSSBlock("/styles/ie6.css", 6) %>
<%= Html.CSSBlock("/styles/ie7.css", 7) %>
<asp:ContentPlaceHolder ID="AdditionalCSS" runat="server" />
</head>
<body>
... BLAH ...
<%= Html.JSBlock("/scripts/jquery-1.3.2.js", "/scripts/jquery-1.3.2.min.js") %>
<%= Html.JSBlock("/scripts/global.js", "/scripts/global.min.js") %>
<asp:ContentPlaceHolder ID="AdditionalJS" runat="server" />
</body>
Html.CSSBlock & Html.JSBlock are obviously my own extensions but again, they are self explanatory in what they do.
Then in say a SignUp.aspx view I would have
<asp:Content ID="signUpContent" ContentPlaceHolderID="AdditionalJS" runat="server">
<%= Html.JSBlock("/scripts/pages/account.signup.js", "/scripts/pages/account.signup.min.js") %>
</asp:Content>
HTHs,
Charles
Ps. I would agree with Andrew in saying that any common JS that is defined directly inside the master page should be concatenated and minified.
EDIT: My implementation of .JSBlock(a, b) as requested
public static MvcHtmlString JSBlock(this HtmlHelper html, string fileName)
{
return html.JSBlock(fileName, string.Empty);
}
public static MvcHtmlString JSBlock(this HtmlHelper html, string fileName, string releaseFileName)
{
if (string.IsNullOrEmpty(fileName))
throw new ArgumentNullException("fileName");
string jsTag = string.Format("<script type=\"text/javascript\" src=\"{0}\"></script>",
html.MEDebugReleaseString(fileName, releaseFileName));
return MvcHtmlString.Create(jsTag);
}
And then where the magic happens...
public static MvcHtmlString MEDebugReleaseString(this HtmlHelper html, string debugString, string releaseString)
{
string toReturn = debugString;
#if DEBUG
#else
if (!string.IsNullOrEmpty(releaseString))
toReturn = releaseString;
#endif
return MvcHtmlString.Create(toReturn);
}
In my website, www.trailbehind.com, we have a set of javascript files that belong on all pages. And then some pages include additional libraries.
For the JS files that all pages uses (there are a couple dozen files), we concatenate them and minify them on build.
There is a flag in our settings file that says whether to use the concatenated javascript or the separate files on build. This is critical so that you can debug the javascript on dev, but use the small, single-file javascript on production.
Here is our python code to combine and minify:
import os
import thetrailbehind.lib.jsmin as jsmin
JS_FILES = [ 'lib/json2.js',
'lib/markermanager.js',
'lib/labeledmarker.js',
'lib/rsh/rsh.js',
'lib/showdown.js',
'lib/yui.js',
'lib/dragzoom.js',
'gen/attribute_data.js',
'gen/national-parks.js',
'Widgets/CommentsWidget.js',
'Widgets/Search.js',
'Widgets/MenuWidget.js',
'Widgets/PhotoWidget.js',
'Widgets/ReportList.js',
'Widgets/help.js',
'attributes.js',
'rsh.js',
'map.js',
'mapcontrols.js',
'markers.js',
'amazon.js',
'plan_trip.js',
'init.js',]
def concat(files, base_path, all_file, all_file_min):
if os.path.exists(base_path + all_file):
lasttime = os.path.getmtime(base_path + all_file)
else:
lasttime = 0
out_of_date = False
for file in files:
if os.path.getmtime(base_path + file) > lasttime:
out_of_date = True
break
if out_of_date:
outfile = open(base_path + all_file, 'w')
for file in files:
outfile.write(open(base_path + file).read())
outfile.write("\n")
outfile.close()
alljs = open(base_path + all_file)
allminjs = open(base_path + all_file_min, "w+")
jsmin.JavascriptMinify().minify(alljs, allminjs)
alljs.close()
allminjs.close()
def main():
concat(JS_FILES, '/home/wibge/thetrailbehind/media/javascript/', 'gen/all.js', 'gen/all.min.js')
if __name__ == "__main__":
main()
And here is the Django/HTML template where we switch:
{% if use_all_js %}
script type=text/javascript src=/site_media/javascript/gen/all.min.js>
{% else %}
script type="text/javascript" src="/site_media/javascript/rsh.js">
script type="text/javascript" src="/site_media/javascript/amazon.js">
script type="text/javascript" src="/site_media/javascript/map.js">
A BUNCH OF SEPARATE INCLUDES...etc
{% endif %}

Categories

Resources