How to encapsulate a reusable "control" for ASP.NET MVC 3 + Razor views - javascript

I am looking for best practices on how to create a reusable "control" for use on several MVC 3 views. I could make an Html helper extension method (programmatically or with the declarative helpers in razor) or I could create a partial view.
The trick, in my case is that I need to do more than just dump some HTML in precisely the spot that the view calls the helper/partial. In addition to putting some HTML markup in that spot, I also need to add some javascript code to make it work. Normally, I would put this code elsewhere in the page (e.g. the bottom). This is of course strictly not required. Also, note, the javascript is not control instance specific. In other words, it is possible to write javascript that finds all instances of the control HTMl markup on a page and "activates" it with appropriate events, etc.
I have thought of several possibilities.
Have the helper/partial dump out the HTML and a <script> tag right in the place it is called. This seems like a bad idea since it means the control could only be used once per page.
Have two helpers. One to output the HTML markup, and a second that spits out the javascript. The second would be called only ever once and would be called from the bottom of the page so that the script ends up in the right place. If I invented a second control that was like this, I would have 4 helpers (2 for HTML, 2 for Javascript).
Invent some kind of ScriptManager that controls can register javascript with. The scriptmanager would have some kind of helper that would be added to the bottom of pages and would dump out the javascript for all controls that had registered some snippet of script. The call to the scriptmanager helper could be in the _layout.cshtml so that it automatically happens on any page that needs it. It would do nothing when a page didn't need it. This doesn't seem very MVC-ish, I guess.
Just have a helper that spits out the HTML and then add the javascript to the site.js that is included on every page. The javascript would be smart enough to not do anything if it could not find any relevant markup on the page (markup would have a wrapper element with a particular class). There would be overhead of this search for markup on all pages though, including pages that don't have any of these controls.
Same as #4, but put the javascript in its own .js file and include it only on pages that use the control. This is more efficient for pages that don't use the control, but it is an additional .js file and associated HTTP request for pages that do.
I am leaning towards #4, but is this a solved problem? Is there a better, 6th option?

My company is employing MVCContrib portable areas to package the code into a DLL for reusable "components"
Each of these components can be called via an extension method. For example:
Html.Components().ShowPoll();
Within each of these components, there is a way to register multiple css/js files that are embedded resources. Our main site will extract the resource files and minify + combines them before serving it.
The component will also register any on page event that will be called during the Document.OnReady event of JQuery. This allows each of the components to be mini-sites, standalone functionality with its own routes, models, and views.
Across the entire site, the same zip up JS for all the components are served. One because the file will be cached, and two - removes the complexity of determining what components are on the page and the resources it needs.
Let me know if you want more information regarding this setup.

I managed this issue with a layout page that had a section called jsCode.
#RenderSection("jsCode",false)
Then when I need it, I create in the content page:
#section jsCode
{
<script type="text/JavaScript" src="myJsCode.js"></script>
}
you could also create a helper that spits out the scripts you need for a particular page and encapsulate it that way, like this:
#helper MyJSFunction(string FunctionName){
switch(FunctionName)
{
case "firstFN":
<text>
<script type="text/JavaScript">
function SaySomethingSilly()
{
var sillySaying="We are the knights who say 'ni'!";
alert(sillySaying);
}
</script>
</text>
break;
case "secondFN":
<text>
<script type="text/JavaScript">
function SaySomethingElse()
{ var sillySaying="We are looking for a shrubbery...";
alert(sillySaying);
}
</script>
</text>
break;
}
}
Then my content page (assuming I want both functions) looks like this:
#{
Page.Title="Using helpers to create scripts";}
#section jsCode
{
#JSHelpers.MyJSFunction("firstFN")
#JSHelpers.MyJSFunction("secondFN")
}
<p>It works!</p>
which produced the output:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Using helpers to create scripts</title>
<script type="text/JavaScript">
function SaySomethingSilly()
{
var sillySaying="We are the knights who say 'ni'!";
alert(sillySaying);
}
</script>
<script type="text/JavaScript">
function SaySomethingElse()
{ var sillySaying="We are looking for a shrubbery...";
alert(sillySaying);
}
</script>
</head>
<body>
<p>It works!</p>
</body>
</html>
Now if you wanted to get super-efficient, (though other words come to mind) you could pass the function a JSON array or a dictionary or even a string array with the names of the scripts you wanted to use, or the JavaScript to import, or whatever, and just use a single call to the helper. I think separate calls is easier to maintain, regardless of how you load the return values of the helper function, because you can see cleanly at a glance which scripts you are using on a given page, and to eliminate or add one is a simple one-line change rather than changing one element of an array.
As always, your mileage may vary, but I ran the sample based on this code in WebMatrix Beta 2 without any issues.
Lisa Z. Morgan
http://www.lairhaven.com

Related

Same sidebar across webpages

I'm pretty new to web development. What is the best practice in keeping the same sidebar and other elements across web pages on one's site? Do you store the sidebar html and call that? If so, how would one go about doing something like that?
There're many options to handle this problem but I've found easy one using jQuery. Use this if it suits your requirements.
Add the jQuery CDN in your HTML file.
Create a JS file as sidebar.js.
Copy all your HTML code of the sidebar and store as a string variable in a function of the JS file. as
function loadNavbarDiv() {
String navbar_code_str = '<nav><div>...</div></nav>
$('body').append(navbar_code_str);
}
Then in the HTML file, you want to add navigation bar, add folowing code in your <head>
<script src="sidebar.js"></script>
<script>
$(document).ready(function(){
loadNavDiv();
});
</script>
It's working fine for me.
Happy coding!
Here's one way to do it: use "include" files. No JavaScript required. The server does the work, instead of requiring the client to add the content.
SSI, or Server Side Includes, were first developed to allow Web
developers to "include" HTML documents inside other pages. If your Web
server supports SSI, it's easy to create templates for your Web site.
Save the HTML for the common elements of your site as separate files.
For example, your navigation section might be saved as navigation.html
or navigation.ssi.
Use the following SSI tag to include that HTML in each page.
<!--#include virtual="path to file/include-file.html" -->
Use that same code on every page that you want to include the file.
That page also describes some other approaches. But if you know this is called using include files, you can search for it more easily. For example, this article describes includes and how to call them from JavaScript if you must.
As long as you're only coding in html, you will need to copy your html into every page. You can store the css for the sidebar in one and the same file and call that on every page though.
Other scripting languages and frameworks might contain templates (php) or master pages (asp.net) for example which make it possible to use the same code in different pages.

Javascript for every single page?

I have some simple JQuery / Javascript to perform some simple logic for all external hyperlinks:
<script>
$("a[href^='http://']:not([href*='"+location.hostname+"']),[href^='https://']:not([href*='"+location.hostname+"'])")
.addClass("external")
.attr("target","_blank")
.attr("title","Opens new window").click(function(e) {alert('You are leaving mysite and going somewhere else, you crazy dude')});
</script>
This is fine for one page. However, I wish to have this in every web page in my application and be 100% sure that it is there.
Is there any good trick to do this?
The only one I can think of is if you are using a java architecture, to have a base JSP and ensure the base JSP calls this.
Any better ideas?
You don't need some server side framework... If you use some templating library (jade handlebars, mustache, jquery templates) or if you simply separate out your HTML files you can pull them each in with jquery and render them on the page. Check out the .load function.
Also, you should separate out your html pages even if they are static.
Wrap it in a function and call the function. Then you can just call the function and leave the implementation to the function call.
Since you didn't specify a server side technology such asp.net or php of course there would be other options (partial views or templates) using that.
function doStuff(){
$("a[href^='http://']:not([href*='"+location.hostname+"']),
[href^='https://']:not([href*='"+location.hostname+"'])")
.addClass("external")
.attr("target","_blank")
.attr("title","Opens new window").click(function(e) {alert('You are leaving mysite and going somewhere else, you crazy dude')});
}
<script>
doStuff();
</script>
This depends on how your site is structured. If you've got a server-side framework (like your JSP example), then you can have a function that makes sure that the script somehow gets included.
If you just have static HTML pages, my recommendation would be to put that code in a script file (let's say dontleaveme.js). Then on every page, just do
<script src="dontleaveme.js"></script>
A good application design will have a layout file or header and footer files which are used on every page. Then it is easy to make changes, such as adding a script, which affect every page on the site. If you are not using this technique, this is a great reason to start.

ASP.NET: How to (programmatically) attach a <script> tag, containing a link to .js, to <head>?

This is the scenario:
I'm working on a new ASP.NET application that uses master pages for virtually all of the web pages in it, a few of them nested to 4 levels. Due to the size of the project, I was forced to organize the web pages into folders, at various depth levels. The global, Master (in uppercase) page, located at the root directory, contains some useful Javascript functions that are used all along the web app, and I wanted to place these functions together in a single .js file, in order to keep things, well, in order :D . (They're currently embedded into the Master page).
I discovered recently, however, that <script> tags placed on the <head> block can't have their paths specified as, for example, "~/Scripts/Utils.js", since ASP.NET does not seem to recognize these paths on <script> tags (yet, strangely enough, it does recognize them on <link> tags). I'm trying to avoid inserting a <script> tag on every single web page on the site specifying a relative path to the .js file (that's sort of why I wanted to use master pages in the first place).
So, in essence, given this scenario, I want to ask you, what's the recommended way of inserting, via code, <script> tags into the <head> block of a web page so that I can use, when specifying the link to the .js file, something like Something.Something(Something, Page.ResolveURL("~/Scripts/Utils.js")); in the global Master page, so it will resolve to the right path on all the web pages of the application, no matter what directory are they inside?
Or is this not the right approach, and I should be using something else entirely?
You can use the ClientScriptManager:
Page.ClientScript.RegisterClientScriptInclude("MyScript", ResolveUrl("~/Scripts/MyScript.js"));
The first argument is a unique key representing the script file, this is to stop subsequent scripts being registered with the same key. E.g. you may have some shared code that does the same thing and could be executed multiple times, so by specifying a key, you ensure the script is only registered the once.

Calling a JavaScript object class that's in a separate .js file

I have created a string builder JavaScript object and I'm using it with many different .js files in my project.
Can I create this class in a separate .js file and call it from all the other scripts that instansiate it, just like a C# class file?
Is this possible, or do I continue copying and pasting it into the bottom of every .js file that uses it?
Yes, this should not be a problem. Just include the .js files in the correct order in your html pages.
If you include the file in your main HTML page with your other js, you can then use the "class" as you wish:
<script src="js1.js" type="text/javascript"></script>
<script src="js2.js" type="text/javascript"></script>
In the above example, you can now instantiate a new instance of an object from js1.js with the code in js2.js. To do this with pure javascript, you would have to add the script tag to the DOM, or use AJAX to fetch the script file and eval() it.
// Create a <script> element
var scriptEl = document.createElement("script");
scriptEl.src = "js2.js";
scriptEl.type = "text/javascript";
// Append it to the <head>
document.getElementsByTagName("head")[0].appendChild(scriptEl);
To be perfectly correct, it's not the order of inclusion that matter, but rather the order of executing code. In most cases, Andy's and Segfault's instructions are just fine, but sometimes including the class file before its consumers isn't sufficient. For example, if you use ExtJS and you happen to define your class inside an onReady handler like this:
Ext.onReady(function() {
myClass = ...
}.bind(this));
then it won't get executed by the time your second src file is included into the page and executed.
I know, the example is a bit far-fetched :) but just make sure that your code is executed in the right order, not just included in the right order.
I came across this question and I wanted to add something (which probably wasn't there a few years ago).
Even thought you can add every single script to your "index.html" it's not a very beautiful practice (imho). Especially if you consider that you may want to write a extension (~ framework). You don't want to annoy the user with a bunch of script tags he has to add to his code. What you want is a single line like this:
<script src="yourFramework" (...) />
However, with the use of RequireJS you are able to achieve this. You've the freedom to separate your code and "your user" still don't have to add a novel to his "script section".

Executing groovy statements in JavaScript sources in Grails

There are essentially 2 places to define JavaScript functions in Grails, directly in a element on the GSP, and within a separate javascript source file under /web-app/js (for example, application.js). We have defined a commonly reused javascript function within application.js, but we also need to be able to generate parts of the function dynamically using groovy code. Unfortunately, ${some groovy code} does not appear to be processed within separate javascript source files.
Is the only way to do this by defining the javascript function within a script tag on a GSP page, or is there a more general solution? Obviously we could define the javascript function in a script tag within a template GSP file which would be reused, but there is a lot of push to keep our javascript functions defined all together in one place (i.e. the external javascript source file). This has performance benefits as well (the javascript source files are usually just downloaded once by each client's browser, instead of reloading the same javascript functions within the source of every html page they visit). I have toyed around with the idea of breaking the function up into static and dynamic pieces, putting the static ones in the external source and putting the dynamic ones in the template GSP, then gluing them together, but this seems like an unnecessary hack.
Any ideas?
(edit: It may sound like the idea of dynamically generating parts of a JavaScript function, which is then downloaded once and used over and over again by the client, would be a bad idea. However, the piece which is "dynamic" only changes perhaps once a week or month, and then only very slightly. Mostly we just want this piece generated off the database, even if only once, instead of hard coded.)
An easy solution to keep your JavaScript unobtrusive is to create a JavaScriptController and map its actions "/js/*" by adding this to your UrlMappings.groovy file:
"/js/$action"{
controller = "javascript"
}
then just create an action for each dynamic JS file you want, include in in your layout <HEAD>, and presto, you've got a JS file that you can insert Grails snippets into! :)
Note: I've found that there's currently a bug in Grails that doesn't map file extensions to content-types properly, so you'll need to include <%# page contentType="text/javascript; UTF-8" %> at the top of your view files.
This is a great solution. I would like to offer a suggestion to use somthing other then a mapping of "/js/$action" because this is no longer going to allow you to access you javascript files in /web-app/js/. All your javascript files would have to be moved to a the directory your controller would point to.
I would use something like
"/dynjs/$action"
This way you still can point to files in the /web-app/js/ files with out conflict and enjoy the benifits of gsp tags in javascript files
Please correct me if I'm wrong.
Or this... have a tag/service/dynamic method that lets tags write out their JS+CSS+whatever else, to a "cache" which is used to build the JS+CSS resources by a different controller.
Full concept here: [http://www.anyware.co.uk/2005/2009/01/19/an-idea-to-give-grails-tags-esp/][1]
If you want to use models created by the controller (that rendered HTML page which reference the Javascript in which you intend to use groovy code) in the Javascript code, then you can use this technique:
This technique does not need to change URL mappings and does not require you to create extra controller.
In your view GSP add javascript as follows:
<script type="text/javascript">
<g:render template="/javascript/yourJavascriptFile"/>
</script>
In views folder create a "javascript" folder. And create a file named:
_yourJavascriptFile.gsp
You can not only use all the GSP code in your _yourJavascriptFile.gsp file, but you can also use all the models created in your controller (that is rendering the view).
NOTE: There is nothing special about javascript folder. You can name it anything you want OR use an existing view folder. This is just a matter of organizing and identifying your HTML spitting GSP from Javascript spitting GSPs. Alternatively, you can use some naming conventions like: _something.js.gsp etc.
Name your scripts like this
/wherever/the/js/files/are/thescript.js.gsp
The gsp code inside will be rendered correctly by grails. This works, but I have no idea if it's considered a Good Idea or not.
There is another way - pass in the generated code into a function that expects closures. Those closures is generated by the program of course. The generated code is of course inlined/script-tagged in the gsp page.
it may or may not work depending on the nature of the code being generated. But i suspect it will work, and if it doesnt, minor tweaking to the coding style of your javascript will definitely make it work. Though, if these 'generated' code doesnt change much, this quite overkill imo.

Categories