http://www.sitepoint.com/using-requirejs-AngularJS-applications/

While writing large JavaScript applications, one of the simplest things one can do is divide the code base into several files. Doing this improves maintainability of the code but increases the chances of missing or misplacing the script tag on your main HTML document. Keeping track of the dependencies becomes difficult as the number of files increases. This issue persists in large angularjs applications as well. We have a number of tools in place that take care of loading dependencies in the application.

In this article, we will see how to use RequireJS with AngularJS to make the job of loading dependencies simpler. We’ll also examine how to use Grunt to generate combined files containing the RequireJS modules.

A Brief Introduction to RequireJS

RequireJS is a javascript library that helps in lazily loading JavaScript dependencies. Modules are just JavaScript files with some RequireJS syntactic sugar in them. RequireJS implements Asynynchronous Modules specified by CommonJS. RequireJS offers simple APIs to create and refer to modules.

RequireJS needs a main file that contains the basic configuration data such as paths to modules and shims. The following snippet shows the skeleton of a main.js file:

require.config({
map:{
// Maps
},
paths:{
// Aliases and paths of modules
},
shim:{
// Modules and their dependent modules
}
});

All modules in the application need not be specified in the paths section. Others can be loaded using their relative paths. To define a module, we need to use the define() block.

define([
// Dependencies
], function(
// Dependency objects
){ function myModule() {
// Can use the dependency objects received above
} return myModule;
});

A module may have some dependent modules. In general, an object is returned at the end of a module, but it is not mandatory.

Angular’s Dependency Injection vs RequireJS Dependency Management

One of the common questions that I hear from Angular developers regards the difference between Angular’s dependency management and that of RequireJS. It is important to remember that the purpose of both the libraries is totally different. The dependency injection system built into AngularJS deals with the objects needed in a component; while dependency management in RequireJS deals with the modules or, JavaScript files.

When RequireJS attempts to load a module, it checks for all dependent modules and loads them first. Objects of loaded modules are cached and they are served when same modules are requested again. On the other hand, AngularJS maintains an injector with a list of names and corresponding objects. An entry is added to the injector when a component is created and the object is served whenever it is referenced using the registered name.

Using RequireJS and AngularJS together

The downloadable code included with this article is a simple application containing two pages. It has the following external dependencies:

  • RequireJS
  • jQuery
  • AngularJS
  • Angular Route
  • Angular Resource
  • Angular UI ngGrid

These files should be loaded directly on the page in the order they are listed here. We have five custom script files containing code of the required AngularJS components. Let’s take a look at how these files are defined.

Defining AngularJS Components as RequireJS Modules

Any AngularJS component consists of:

  • A function definition
  • Dependency Injection
  • Registering to an Angular module

Out of the above three tasks, we will perform the first two tasks inside the individual modules, while the third task will be performed in a separate module that is responsible for creating the AngularJS module.

First, let’s define a config block. The config block doesn’t depend on any other blocks, and returns the config function in the end. But, before we load config module inside another module, we need to load everything that is needed for the config block. The following code is 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;
});

Notice the way dependency injection is performed in the above snippet. I used $inject to get the dependencies injected as the config function defined above is a plain JavaScript function. Before closing the module, we return the config function so that it can be sent to the dependent module for further use.

We follow the same approach for defining any other type of Angular component as well, as we don’t have any component specific code in these files. The following snippet shows the definition of a controller:

define([], function() {
function ideasHomeController($scope, ideasDataSvc) {
$scope.ideaName = 'Todo List';
$scope.gridOptions = {
data: 'ideas',
columnDefs: [
{field: 'name', displayName: 'Name'},
{field: 'technologies', displayName: 'Technologies'},
{field: 'platform', displayName: 'Platforms'},
{field: 'status', displayName: 'Status'},
{field: 'devsNeeded', displayName: 'Vacancies'},
{field: 'id', displayName: '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 Angular module for the application depends on each of the modules defined up to this point. This file gets objects from all other files and hooks them with an AngularJS module. This file may or may not return anything as the result of this file, the Angular module can be referenced from anywhere usingangular.module(). The following code block defines 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',ideasDataSvc);
app.controller('ideasHomeController', ideasHomeController);
app.controller('ideaDetailsController',ideaDetailsController);
});

The Angular application cannot be bootstrapped using the ng-app directive as the required script files are loaded asynchronously. The right approach here is to use manual bootstrapping. This has to be done in a special file called main.js. This needs the file defining the Angular module to be loaded first. The code for this file is shown below.

require(['app/ideasModule'],
function() {
angular.bootstrap(document, ['ideasApp']);
}
);

Configuring Grunt to Combine RequireJS Modules

While deploying a JavaScript heavy application, the script files should be combined and minified to optimize download speed of the script files. Tools like Grunt come handy to automate these tasks. It has a number of tasks defined to make any process of front-end deployment easier. It has a task, grunt-contrib-requirejs for combining RequireJS files modules in the right order and then minifying the resulting file. Just like any other grunt task, it can be configured to behave different for each stage of deployment. The following configuration can be used in the demo application:

requirejs: {
options: {
paths: {
'appFiles': './app'
},
removeCombined: true,
out: './app/requirejs/appIdeas-combined.js',
optimize: 'none',
name: 'main'
},
dev:{
options:{
optimize:'none'
}
},
release:{
options:{
optimize:'uglify'
}
}
}

This configuration would produce an unminified file when Grunt is run with the dev option, and a minified file when grunt is run with the release option.

Conclusion

Managing dependencies becomes challenging when the size of the application grows beyond a certain number of files. Libraries like RequireJS make it easier to define the dependency and not worry about the order of loading of the files. Dependency management is becoming an integral part of the JavaScript applications. AngularJS 2.0 is going to have built-in support for AMD.

Using RequireJS in AngularJS Applications的更多相关文章

  1. [Angular] Use Angular components in AngularJS applications with Angular Elements

    When migrating AngularJS (v1.x) applications to Angular you have different options. Using Angular El ...

  2. 关于RequireJS与AngularJS的集成文档

    为什么要整合RequireJS RequireJS是一个Javascript 文件和模块框架,通过模块的方式来配置js文件之间的依赖关系,遵守的是CommonJS的AMD标准. 在开发的时候则无需关注 ...

  3. Integrating AngularJS with RequireJS

    Integrating AngularJS with RequireJS When I first started developing with AngularJS keeping my contr ...

  4. AngularJS快速入门指南12:模块

    AngularJS模块定义了一个application. 模块是一个application中不同部分的容器. application中的所有控制器都应该属于一个模块. 带有一个控制器的模块 下面这个a ...

  5. angularjs与require的集成摘抄

    基于requireJS和angularJS的前端技术架构 :http://blog.163.com/liuyong_xiaxia/blog/static/17435525520156341446981 ...

  6. AngularJS快速入门指南05:控制器

    AngularJS控制器用来控制AngularJS applications的数据. AngularJS控制器就是普通的JavaScript对象. AngularJS控制器 AngularJS app ...

  7. AngularJS快速入门指南02:介绍

    AngularJS是一个JavaScript框架.它可以通过<script>标记被添加到HTML页面中. AngularJS通过指令对HTML属性进行了扩展,然后通过表达式将数据绑定到HT ...

  8. trackr: An AngularJS app with a Java 8 backend – Part II

    该系列文章来自techdev The Frontend 在本系列的第一部分我们已经描述RESTful端建立在Java 8和Spring.这一部分将介绍我们的第一个用 AngularJS建造的客户端应用 ...

  9. AngularJS基础总结

    w3shools    angularjs教程  wiki   <AngularJS权威教程> Introduction AngularJS is a JavaScript framewo ...

随机推荐

  1. Python+Visual Studio

    一直在找一个比较好的Python IDE,无奈找来找去都不太好用,由于经常用Visual Studio,所以很希望找到一个能够在VS中的Python扩展.今天发现了一个很给力的VS扩展,可以在VS中方 ...

  2. 【一天一道LeetCode】#36. Valid Sudoku

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:https://github.com/Zeecoders/LeetCode 欢迎转载,转载请注明出处 (一)题目 Determi ...

  3. 【翻译】了解Ext JS 5的小部件

    原文:Understanding Widgets in Ext JS 5 在Ext JS 5,引入了新的"widgetcolumn",支持在网格的单元格中放置组件.同时,还在Ext ...

  4. python的IndentationError: unexpected indent python

    都知道python是对格式要求很严格的,写了一些python但是也没发现他严格在哪里,今天遇到了IndentationError: unexpected indent错误我才知道他是多么的严格.    ...

  5. mysql进阶(二)索引简易教程

    Mysql索引简易教程 基本概念 索引是指把你设置为索引的字段A的内容储存在一个独立区间S里,里面只有这个字段的内容.在找查这个与这个字段A的内容时会直接从这个独立区间里查找,而不是去到数据表里查找. ...

  6. PYTHON风格规范-Google 开源项目风格指南

    Python风格规范 分号 Tip 不要在行尾加分号, 也不要用分号将两条命令放在同一行. 行长度 Tip 每行不超过80个字符 例外: 长的导入模块语句 注释里的URL 不要使用反斜杠连接行. Py ...

  7. 【一天一道LeetCode】#18. 4Sum

    一天一道LeetCode (一)题目 Given an array S of n integers, are there elements a, b, c, and d in S such that ...

  8. 四种简单的图像显著性区域特征提取方法-----AC/HC/LC/FT。

    四种简单的图像显著性区域特征提取方法-----> AC/HC/LC/FT. 分类: 图像处理 2014-08-03 12:40 4088人阅读 评论(4) 收藏 举报 salient regio ...

  9. OpenCV轮廓检测,计算物体旋转角度

    效果还是有点问题的,希望大家共同探讨一下 // FindRotation-angle.cpp : 定义控制台应用程序的入口点. // // findContours.cpp : 定义控制台应用程序的入 ...

  10. UML之时序图

            时序图,英文名曰:Sequence Diagram,也称顺序图和序列图,是一种行为图,她通过描述对象之间发送消息的时间顺序显示多个对象之间的动态协作.她可以表示用例的行为顺序,当执行一 ...