How RequireJS Plays a Role in Angular?
It’s the best way of simplifying the task of loading dependencies using AngularJS and RequireJS
One of the basic steps that need to be taken while writing big JavaScript apps is the division of the code base into numerous files. Not only does this help to enhance the maintainability of the code but it increases the possibility of misplacing or missing the script tag on the primary HTML document.
With the increase in the number of files, keeping up a clean record of all the dependencies becomes rather complicated and this issue extends to the case of large AngularJS apps as well. There are few tools that can handle the loading dependencies in the application.
It is important to know the best way of simplifying the task of loading dependencies by using RequireJS with AngularJS along with the way in which Grunt must be used for the purpose of generating combined files holding the RequireJS modules.
Understanding the Basics of RequireJS
RequireJS is a JavaScript library that assists with the loading of JavaScript dependencies at a slow pace. Modules are basically JavaScript files with a few RequireJS syntactic sugar in them and so, RequireJS is capable of implementing the Asynchronous Modules that are specified by the Common JavaScript. You attain the benefit of creating and referring to modules by using the simple APIs offered by RequireJS.
RequireJS should always have a main file that holds the basic configuration data like shims and path modules. The snippet below explains the basic outline of a main.js file:
require.config ( {
map: {
// Maps
},
paths: {
// duplicate names and path of the
modules
},
shim: {
// Modules, plus their dependent modules
}
} );
Every module present within the application does not need to be specified within the paths section and others may be loaded with the help of their relative paths. However, when defining a particular module, the define( ) block needs to be used.
define ( {
// Dependencies
], function (
// object with dependency
){
function yourModule ( ) {
// dependency objects received above
can used
}return yourModule;
});
It is possible for a module to have a few dependent modules but in general, an object will be returned by the end of the module. However, this outcome is not mandatory.
Comparison of RequireJS Dependency Management with Angular’s Dependency Injection:
The difference between RequireJS dependency management and Angular’s dependency management is one of the most frequently asked questions by Angular developers.
While RequireJS tries to load a module, it checks for every dependent module and proceeds to load them first. The objects of the loaded modules are cached and later, they get served when the same page requests once again. However, AngularJS possesses an injector that contains a list of names as well as corresponding objects. Upon creation of a component, an entry is added to the injector and the object gets served whenever it is referenced via the registered name.
Using AngularJS and RequireJS Together:
Most codes for simple applications contain various external dependencies, including:
- RequireJS
- Angular Resource
- jQuery
- AngularJS
- Angular UI’s ngGrid (Or any component library)
- Angular Route
All of the above-mentioned files need to be loaded directly on to the page in a specific order.
How to Define AngularJS Components In Terms of Requirejs Modules?
Almost every AngularJS component is made up of:
- The Dependency injection
- A function definition
- Finally, registering with an Angular module
The first step involves defining a config block which does not depend on other blocks and is capable of returning the config function in the end. However, prior to loading the config module within another module, it is necessary to load every essential component required for the config block. The code below will be contained in config.js:
define ( [ ],function(){
function config($routeProvider) {
$routeProvider.when(‘/home’,{templateUrl:’
templates/home.html’,
controller:’ideasHomeController’})
.when(‘/details/:id’,{templateUrl:’templates/
ideaDetails.html’,
controller:’ideaDetailsController’})
.otherwise({redirectTo:’/home’});
}
config.$inject=[‘$routeProvider’];
return config;
});
The integral point to take note of is the way in which the dependency injection has been carried out in the code snippet above. $inject was used to get the dependencies injected while the config function defined above happens to be a plain JavaScript function. Prior to closing the module, config function must be returned so that it might be sent to the dependent module for use in the future.
The same approach may be followed for defining other kinds of Angular components also, since there is no component specific code contained in the files. The snippet below exhibits the definition of the controller:
define ( [ ], function() {
function ideasHomeController($-
scope, ideaDataSvc) {
$scope.ideaName = ‘Todo List';
$scope.gridOptions = {
data : ‘ideas’,
columnDefs: [
{ field:’name’, displayname:’Name’},
{ field:’technologies’,displaName:’
Technologies’},
{ field:’platform’,displaName:’Platforms’}
{ field:’status’,displaName:’Status’},
{ field:’devesNeeded’,displaName:’
Vacancies’},
{ field:’id’,displaName:’View Details’,
‘cellTemplate:'<a ng-href=”#/details/{{
row.getProperty(col.-
field)}}”>View Details</a>’}
],
enableColumnResize: true
};
ideasDataSvc.allIdeas( ).then(function(
result) {
$scope.ideas=result;
});
}
ideasHomeController.$inject=[‘$
scope’, ‘ideasDataSvc’];
return ideasHomeController;
});
The application’s Angular module is based on each of the modules that have been defined till this point. The file gains objects from all the other files and then hooks them in with an AngularJS module. It is possible that the file may or may not return something as the result of this file, but the Angular module may be referenced from anywhere with the help of angular.module( ). The following blocks of code define an Angular module:
define([‘app/config’,
‘app/ideasDataSvc’,
‘app/ideasHomeController’,
‘app/ideaDetailsController’],
function(config, ideasDataSvc, ideasHomeController,
ideaDetailsController) {
var app = angular.module(‘
ideasApp’, [‘ngRoute’,’ngResource’,
‘ngGrid’]);
app.config(config);
app.factory(‘ideasDataSvc’,ideas-
DataSvc);
app.controller(‘ideasHomeController’,
ideasHomeController);
app.controller(‘ideaDetailsController’,
ideaDetailsController);
});
No Angular application can be bootstrapped using the ng-app directive since the necessary files are loaded in asynchronous manner. The right approach here involves the use of manual bootstrapping and needs to be done in a special file named main.js. This requires the file defining the Angular module to be first loaded and the code is given below:
require {[‘app/ideasModule’],
function( ) {
angular.bootstrap(document,
[‘ideasApp’]);
}
);
Conclusion:
The process of managing dependencies tends to pose a challenge when the application size exceeds beyond a specific number of files. Libraries such as RequireJS make it simpler to define the dependency without having to worry about the loading order of the files. Dependency management involves becoming an essential part of the JavaScript applications. AngularJS 2.0 will receive the benefit of built-in support for AM