How does RequireJS work with multiple pages and partial views? - asp.net-mvc

I'm looking into RequireJS but I'm uncertain about some things.
I understand how I can load all my dependencies with main.js.
But do I need to add any logic to work with those dependencies in main.js?
To me, main.js seems like a document.ready state and you enter logic there when the document has loaded, right?
And for other pages and partial views, do I need to create multiple main.js or can I just reference loaded functions in dependencies from the views in a <script> for example?

Update -
I've added an example of using RequireJS with modular HTML components. Build tool example included - https://github.com/simonsmith/modular-html-requirejs
I have also written a blog article about this - http://simonsmith.io/modular-html-components-with-requirejs/
The approach of just using main.js for everything is probably more suited to a single page application.
The way I've handled this situation is to only include common site-wide JS in the main.js file:
On every page:
<script src="require.js" data-main="main"></script>
main.js
require.config({
// config options
});
require(['jquery', 'common/ajaxLoader', 'common/someOtherModule'], function($, ajax, otherModule) {
// Modules that do stuff on every page are instantiated here
});
page1.html
<script>
require(['scripts/page1']);
</script>
page1.js
require(['jquery', 'page1Module'], function($, module){
// page1 specific stuff here
});
The above example is just one of a couple of ways to handle it. Note the difference between loading a plain JavaScript file and a module.
A rule of thumb I follow is to keep all reusable modules (or Classes if it makes it easier to conceptualise) inside a define with their own dependencies etc and then use require to grab those modules, use their methods or interact with them in some way.
Using this pattern will almost certainly require use of the domReady module that is a separate plugin for RequireJS. Use this instead of a ready function in jQuery for example, as it allows modules to begin downloading before the DOM is ready which reduces the wait for your code to execute.
Edit You may wish to see another example of multi-page application in the RequireJS repo

I have recently gone through the exercise of setting up RequrieJS with automatic build optimization in an ASP.NET MVC application. There are a lot of helpful blog articles such as Simon's that are a great reference. From an ASP.NET perspective one of the most useful I found in terms of configuring the RequireJS optimizer for multi-page ASP.NET applications was Making RequireJS play nice with ASP.NET MVC.
Using the great information already out there I have put up my own ASP.NET MVC RequireJS example on GitHub. Much of what is included is similar to examples already out there, however to address the issue of partial views, and multi-page require dependencies I have taken a slightly different approach.
_Layout.cshtml
The most notable difference from existing examples is the creation of a custom RequireViewPage that exposes methods to pass configuration data to RequrieJS as well as reference page specific require dependencies.
So your _Layout.cshtml will look much like what you'd expect with:
<head>
...
#RenderModuleConfig()
<script type="text/javascript" src="#Url.Script("vendor/require.js")" data-main="main"></script>
</head>
<body>
...
Views & Partials
To wire up views (and in my case knockout view models), an additional script fragment has been added to the bottom of _Layout.cshtml as follows
...
#RenderSection("scripts", required: false)
<script type="text/javascript">require(['main'], function () { require(['lib/knockout/knockout.require']); });</script>
</body>
This will ensure that for any view dependency, the main module has been loaded (assuming dependencies for main have being defined in main.js and then allows for view specific dependencies to be wired up via data attributes.
<div data-require="#MainModule"> ... </div>
<div data-require="#Module("address")"> ... </div>
<div data-require="view\home\index\model"> ... </div>
For a full explaination of the design and choices, see the README on GitHub

Related

section scripts vs script-tag in asp.net mvc

What is the difference of both statements concerning the section Scripts and script-tag? NOT the content inside the scripts that does not interest me.
#section Scripts {
#Scripts.Render(Bundles.Scripts.Validation)
}
vs
<script src="#Url.Content("~/Scripts/Validation.js")"></script>
The first one renders the <script> tag where you have #RenderSection("Scripts") in your layout.
This is preferred when you don't have to include a script for all pages.
Also #Scripts.Render will minify and bundle your scripts. Usually this is used at the end of body tag so that Views can get the scripts after the DOM is rendered.
The second one remains where you use the <script> tag.
If you use it in Layout, the script is included in all pages (e.g. jQuery).
Let's take an example
<!-- HTML in Layout, before Scrip -->
#RenderBody()
<script src="#Url.Content("~/Scripts/jquery.min.js")"></script>
#RenderSection("Scripts")
<!-- HTML after Script -->
Here, if the script make use of jQuery you want to included with section because jQuery is included before section.
If you include with <script> in your view you will give an error, that jQuery is missing, because is included before jQuery.
You might want to define sections in you _layout.cshtml file for specific content. It is generally believed that styles belong to <head> and scripts belong before </body>. Your mileage may vary.
If you just output <script> it will go with all the content and not where you might want it to be.
And if script inside view depends on something (jquery) and in your layout you have
#renderBody()
<script src=jquery.js></script>
#renderSection("scripts",required:false)
then you are screwed (-:

Difference Between Script Rendering Code in Razor

When I create an MVC project that uses Razor, the following lines are generated:
#Scripts.Render("~/bundles/jquery")
#RenderSection("scripts", false)
What is the difference between these lines ? Is it the case that #Scripts.Render generates a <scripts> section and then #RenderSection("scripts", false) renders it ?
The first one renders out a bundle, which is a group of related Javascript files. For instance, you might want to bundle jQuery and jQuery UI together. Bundles also get the benefit of bundling and minification when a solution is compiled in release mode. ref: http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification
#RenderSection indicates that a page that uses the layout in question can inject markup in a particular spot in the layout. Sections are in effect a placeholder (and work much like the ContentPlaceHolder server control from web forms if you are familiar with that). That reference is probably right before the closing body tag, where it is believed by some to be the best spot to put scripts. You could have a section called scripts, or head, or footer, it is completely arbitrary and sections don't necessarily have anything to do with scripts at all. ref: http://weblogs.asp.net/scottgu/asp-net-mvc-3-layouts-and-sections-with-razor
These are completely different things.
The #Scripts.Render("~/bundles/jquery") is rendering a group of scripts for you, creating all the <script> tags. in the BundleConfig.cs file you are able to create bundles of scripts and css files.
One of its advantages allow you to group multiple files that are commonly used together. Instead of including each of these files explicitly you can include all of them using explicit Scripts.Render(groupName).
You can read more about Bundling and Minification here.
The #RenderSection("scripts", false) is about rendering a section in the view.
A section allow you to specify a region of content within a layout. It expects one parameter which is the name of the section. If you don’t provide that, an exception will be thrown.
Here is a good article explaining about Layouts, RenderBody, RenderSection and RenderPage in ASP.NET MVC.
The first parameter to the “RenderSection()” helper method specifies
the name of the section we want to render at that location in the
layout template. The second parameter is optional, and allows us to
define whether the section we are rendering is required or not. If a
section is “required”, then Razor will throw an error at runtime if
that section is not implemented within a view template that is based
on the layout file (which can make it easier to track down content
errors). If a section is not required, then its presence within a
view template is optional, and the above RenderSection() code will
render nothing at runtime if it isn’t defined.

How to dynamically import css with backbone?

I'm developing a app, using backbone, underscore, and jquerymobile. Following jqmobile's way, I have an index page which loads every visited page in special divs tags, flagged with the attribute data-role="page". For each page, i have its corresponding style file (or code snippet embedded in a style html tag). My problem is that the names of my stylable stuff started to collide. Other thing is that I would not like unnecessary style files loaded for each page. Is there any way of dynamically import only the required css for the current page?
I am accomplishing exactly what you ask using RequireJS and the RequireCSS plugin.
Here is a snippet from one of my views:
define([
'jquery',
'underscore',
'backbone',
'views/company/form',
'text!templates/company/company.html',
'css!../../../css/company/company',
], function($, _, Backbone, Form, pageTemplate) {
var Page = Backbone.View.extend({
...
});
return Page;
});
Line 7, 'css!../../../css/company/company' is where the css file becomes a requirement for loading this view.
Once the company.css stylesheet is loaded, it's in the browser even when other "pages" load because there are no actual page refreshes. Thus I have my main page views toggle a class on the <html> element:
// remove any old route-* classes existing on the html element
$('html').removeClassRegEx(/^route-.*/);
// add in the company's top-level class name
$('html').addClass('route-company');
And all my page-specific styles for the company page are scoped to the .route-company class.
You can find the jQuery plugin removeClassRegEx here.
One way of doing that is with jquery (which you 90% are already using with backbone), and its load or get ajax functions, or whatever, plus callbacks.
Then you can call such functions from your backbone app if you need to, and simply inject that css inside <style> tags into your document, as a template.
Or I think there are also specialized jquery functions.
Another way I can think of doing that would be with require.js and it's plugins (it has text plugin, I believe, which will also enable you to load your javascript templates).

Moving unobtrusive javascript out of html.erb file

I have a html.erb file in one of my views. The file is pretty big and has about 2/3 javascript code and just 1/3 html. I dont like this file being too cluttered. The javascript part is mostly event handlers and usage of jquery UI components like date pickers, dialogs etc for the corresponding html elements in the page. I would like to separate the javascript part from the html part.
Can I move the javascript to a separate js.erb file and use it like a partial? What is the advantage of this?
How would I move the javascript to a static .js file when I use rails API like I18n.() and <%= form_authenticity_token %>. Should I pass them every time to the wrapping javascript function? Is there a better way to do this?
If I move javascript out of the html.erb file will it help in caching/rendering of html.erb page?
Interested to find out if there are any re-usable patterns
Sample code on the html.erb file:
<% content_for :javascript do %>
<script type="text/javascript">
$(document).ready(function()
{
$('#create_segment_dialog').dialog({
title: "<%= I18n.t("segment.create_segment_title") %>",
// lots of javascript
}
</script>
<%end %>
//HTML starts here
<div id="right-column">
My 2c, but I know there are differing opinions on this:
Try and separate out as much of your JS code into a function or functions and put them into JS files in your asset pipeline. Take advantage of the move to break your JS into re-usable components that could be used by other methods/controllers.
This means you get all the benefits of the asset pipeline for the JS you move there:
Caching & fingerprinting your JS assets
Minification & compression support to save bandwidth
Minification to obfuscate your code if that is something you want
Concatenation of JS files to reduce the number of requests a browser has to make
Possibility to serve the assets from another location (CDN, web tier vs app tier)
Improved DRYness if that JavaScript is used by other methods/controllers
The drawback? As you've pointed out, any Rails variables have to be passed in as parameters to the functions.
Moving your JavaScript to a .js.erb partial is an option, but if this code is very specific to a particular method or controller then it is not necessarily improving DRYness - it may make your code a little more readable, by separating HTML and JS.

Where in the Rails framework should I place my Backbone templates?

I'm a rails developer trying to learn Backbone and then I ran into this problem: since Underscore templates include symbols like <%=%>, I guess templates can't be included into erb files, so is it okay to have a rails partial for every single template? And what extension should it be?
You can escape the erb symbols by using two % in the opening tag, and put your backbone templates in the rails views:
<script type='text/template' id="my-template'>
<%%= name %>
</script>
will output the following in your page:
<script type='text/template' id="my-template'>
<%= name %>
</script>
Putting your Backbone templates directly in your rails views is IMHO the best option when you're trying to learn. You're already wrestling with the new concepts, no need to add another hurdle.
Starting with Rails 3.1, it provides two things that make working with Backbone templates a little easier: the asset pipeline, and automatic JST (JavaScript Template) compilation.
Create a directory in your app/assets folder called templates. This directory will automatically be picked up by the asset pipeline.
Next, name the files in that directory with an extension of jst and the type of template you are creating ejs (embedded javascript). You can even nest them in directories. For example:
app/assets/templates/my_template.jst.ejs
app/assets/templates/bookmarks/show.jst.ejs
The asset pipeline also allows you to use other templating languages like embedded coffeescript, mustache, handlebars, etc. by simply changing the file extension (and including any necessary gems).
Now to reference your JST templates in your Backbone views, simply use the path to the filename:
var Bookmark = Backbone.View.extend({
template: JST['bookmarks/show'],
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
}
});
You may need to add this line to your application.js:
// require_tree ../templates
Here's a nice article which explains all of this in a little more detail: http://www.bigjason.com/blog/precompiled-javascript-templates-rails-3-1
Where should you put your Backbone templates? I'd say nowhere. I believe that in most Rails applications, the server should be responsible for all rendering of HTML, while the client-side JavaScript should just be responsible for inserting that rendered HTML into the DOM. Among other things, this makes I18n easier.
The exception would be if Rails is simply being used as a lightweight backend for an application that runs mostly on the client side (though in that case, you might want to use Sinatra or something instead). In this case, Rails should probably render nothing, and have the JS do all the rendering.
Notice the underlying principle here. Either the server should be responsible for all rendering, or the client should. Splitting it will make life harder.

Resources