How to Use RequireJS With KnockoutJS in ASP.Net MVC4

This article explains the use of require.js with KnockoutJS in ASP.Net MVC4.

Since I have just begun to learn require.js, today we will explain the use of require.js with KnockoutJS in ASP.Net MVC4. In my last article, we saw how to use KnockoutJS with ASP.Net MVC4.
 
Why RequireJS?
 
"RequireJS is a JavaScript file and module loader. It is optimized for in-browser use, but it can be used in other JavaScript environments, like Rhino and NodeJS. Using a modular script loader like RequireJS will improve the speed and quality of your code" - RequireJS.org
 
Yes, as said above, RequireJS loads the JavaScript files asynchronously and we can access the modules on demand. It is a must for when we develop a fully JavaScript based complex web application.
 
RequireJS gives you the code reusability and manages the dependencies better. For a better understanding, please go through the documentation available in the RequireJS site.
 
RequireJS with KnockoutJS
 
When you are developing a web application using KnockoutJS with ASP.Net MVC4, we need to manage the way in which the models and viewmodel of KnockoutJS part are loaded.
 
In ASP.Net MVC4, we have an option to bundle the knockout JavaScript and CSS so that the script loading time will be less since it loads only one file (bundle) instead of loading each knockout view models many times. But when the bundle is rendered, all the viewmodel and their dependencies will be loaded into memory. But the page would not require all the viewmodel and their dependencies to be loaded into memory, but only the required.
 
This is where RequireJS is used to define and load the knockout model, viewmodel and their dependencies on demand.
 
Let us explain the same with an example.
 
Setup the Project
 
Just follow the steps described in my last article to setup the project environment. Once you are done creating the view and controller, add the require.js file using NuGet Manager as shown in the figure.

image1.gif
 
Right-click on the project file and select the "Manage NuGet Packages...". You will get a window as shown below.

image2.gif
 
Here, select the Online tab in the left side panel and type requirejs in the search box on the top right corner to get it on the list. Once it's listed in the list, click on Install to include the require.js file into your project.
 
Ensure you have the require.js and r.js files added to the Scripts folder.
 
Since we will load the models and view models on demand, it's better to have the separate folder for our knockout models and view models.

image3.gif
 
Please make sure the folder and file name are same as shown in the preceding figure.
 
The app.js
 

The app.js file is the main one that has the initial steps to work on RequireJS.
  1. require.config({  
  2.     paths: {  
  3.         ko: "/Scripts/knockout-2.3.0",  
  4.         jquery: "/Scripts/jquery-1.8.2.min"  
  5.     },  
  6.     baseUrl: "/Js"  
  7. });
Since we will use jQuery and KnockoutJS, we need to force the RequireJS to look for the scripts whenever these files are referenced.
 
RequireJS's Config function accepts an object that has the most important properties. For our example application, we have configured the RequiredJS with two properties paths and baseUrl.
 
paths
 
The paths property accepts an object with properties that have the script file's path to be mapped. In the preceding example code, ko is assigned with the KnockoutJS file path. The path mapping code will automatically add the .js extension when mapping the module name to a path.
 
baseUrl
 
The baseUrl property accepts the string, which is the root path for the model and view model to look into. If the path's mappings path does not begin with "/" then the path's mapping property uses the baseUrl. For example, in the preceding example config, if the path does not start with "/", then require() will calculate the path for ko as /Js/Scripts/knockout-2.3.0.js.
 
For all the config properties please have a look at the config part of the RequireJS site.
  1. require(['ko''jquery''home.index'], function (ko, $, indexViewModel) {  
  2.     $(document).ready(function () {   
  3.         var index = new indexViewModel();  
  4.         ko.applyBindings(index, $('.container')[0]);  
  5.     });  
  6. });
In the code above, the first parameter of require() is a list of module ID's and the second parameter is the callback that will be executed when all the modules are loaded. Please visit the RequireJS site for the various ways of using require().
 
In short, require() loads the modules that are already defined using define().
 
The home.index.js
 
In this file, we have a module (knockout viewmodel) defined using define().
  1. define('home.index', ['ko'], function (ko) {  
  2.     var indexViewModel = function () {  
  3.         var self = this;  
  4.         self.welcomeMessage = ko.observable('Welcome to KnockoutJS + MVC4 world');  
  5.         self.onmousein = function(data, event) {  
  6.             $(event.target).animate({ fontSize: "24px" }, 1500);  
  7.         },  
  8.         self.onmouseout = function(data, event) {  
  9.             $(event.target).animate({ fontSize: "12px" }, 1500);  
  10.         };  
  11.     };  
  12.     return indexViewModel;  
  13. });
In the above define() function, the first parameter is the module ID and the second parameter is the list of dependencies (module IDs) and the third parameter is the callback function that will be executed when all the dependencies are loaded.
 
Note: if you don't set the first parameter, then the module ID will be the module's script file name, in this example if you miss the first parameter then the module ID will be "home.index".

The callback function is supplied with the loaded modules in the same order as the list of modules given (second parameter). The define() function returns the new module indexViewModel. The indexViewModel knockout viewmodel has a welcomeMessage property and two more functions.
 
In short, the define() function defines a module to load using require().
 
The _Layout.cshtml
 
In the _Layout.cshtml view, we just need to add the reference for only the require.js file.
  1. <!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <meta charset="utf-8" />  
  5.         <meta name="viewport" content="width=device-width" />  
  6.         <title>@ViewBag.Title</title>  
  7.         @Styles.Render("~/Content/css")  
  8.         <script type='text/javascript'  
  9.                 data-main="Js/app.js" src="~/Scripts/require.js"></script>  
  10.     </head>  
  11.     <body>  
  12.         <div class="container">  
  13.             @RenderBody()  
  14.         </div>  
  15.     </body>  
  16. </html> 
In the preceding example, we are not using the Bundle feature of ASP.Net MVC4 for scripts since we will require.js for AMD (Asynchronous Module Definition).
 
As in the code above, just add only the require.js file reference. But a new attribute "data-main" is added with the value "Js/app.js".
 
The "data-main" attribute says that after the successful load of require.js, require.js should load the app.js file. The value of data-main attribute is the file path of the application starter script.

image4.gif
 
When the page is rendered, the script tag that require.js generates for your data-main module includes the async attribute. So the application starter file and all the modules will be loaded asynchronously as shown in the preceding figure.
 
The Index.cshtml
  1. @{  
  2.     ViewBag.Title = "Index";  
  3. }  
  4. <h2>Index</h2>  
  5. <div data-bind="text: welcomeMessage, event: { mouseover: onmousein, mouseout: onmouseout }"></div> 
In the index view, we have the knockout text binding to display the welcome message and event binding to animate the text. Just bind the properties and function as shown above to get it to work.
 
If you are not very aware of KnockoutJS then please have a look at these articles to get some basics.
 
Thanks for reading this. Hope you Liked it.
 
Happy Coding