Last Updated: September 15, 2020
·
11.22K
· gerardsans

Angular — Using RequireJs (AMD)

AngularJs Meetup South London Collection | this article

alt text

I am not going to tell you why but how. If you are still curious or feeling insecure, head to the links at the bottom. Now that we have cleared the air, let’s see how to do it.

I find useful to see RequireJs as taking care of file dependencies and Angular module system as taking care of instances with its DI engine. RequireJs makes sure a file is loaded before giving you the control.

Changes to index.html

There are few things to take into account.

Add RequireJs script

First we need to include a reference to RequireJs using the script tag as follows. Pick your preferred setup below.

<!-- basic setup -->
<script
  data-main="main" 
  src="local/path/require.js">
</script>

<!-- advanced setup: using public CDN with local file fallback -->
<script data-main="main" src="http://requirejs.org/docs/release/2.1.14/minified/require.js"></script>
<script>window.require || document.write('<script data-main="main" src="local/path/require.js"></script>')</script>

We are telling RequireJS where to find its configuration with the data-main attribute of the script element.

Note how we omitted the .js extension. This is how RequireJs identifies files by default.

Angular changes

We need to do some changes, to delay Angular bootstrap, until RequireJs finishes loading all file dependencies.

  • Remove ng-app directive. We will bootstrap Angular to the page manually.

  • Add ng-cloak class to the body element and define ng-cloak in your site css file. This will avoid any double curly brackets from showing briefly on slow devices.

RequireJs configuration file — main.js

In main.js we set the configuration options and bootstrap Angular using a init function within the standard Angular app.js file.

// Configuration Options
require.config({
    baseUrl: 'local/path',    
    // paths: maps ids with paths (no extension)
    paths: {
        'angular': 
          ['https://code.angularjs.org/1.3.5/angular',
          //fallback if CDN location fails
          'local/path/angular']
    },
    // shim: makes external libraries reachable
    shim: {
      angular: {
          exports : 'angular'
      }
    }
});

// Angular Bootstrap 
require(['app', 'services', 'controllers'], function (app) {
  // initialisation code defined within app.js
  app.init();
});

In this setup we used services.js and controllers.js files to hold our list of services. You may want to use individual files for extra granularity.

We use require() to load dependencies before running our code.

Changes to app.js

We have wrapped our app module with define having only a dependency from angular. Besides, we have created a init function to manually bootstrap angular to our page.

define(['angular'], function (angular) {
  var app = angular.module('myApp', []);

  app.init = function () {
    angular.bootstrap(document, ['myApp']);
  };

  return app;
});

Returning our app instance will allow us to re-use it on any of our Angular Modules

We use define() to define our modules. This can load dependencies and return an instance for our module.

Changes to Angular Modules

Up to this moment we have only covered our Angular application but left outside other Angular modules (directives, filters, services, controllers). In order to create our modules we will wrap them using define.

define(['app'], function(app) {
  app.controller('MainController', ['$scope', 'Time', function ($scope, Time) {
    $scope.time = Time.getTime();
  }]);
});

MainController

On our setup we don’t need to add a timeService.js dependency as services.js already includes it so it will be loaded before bootstrap and ng-controller instantiation.

Loading Sequence

This is a review of all that’s happening

  • index.html file loads.
  • All script and link tags src/href files are loaded.
  • Once require.js is loaded follows main.js.
  • RequireJs configuration is set. Initial require loads all dependencies and sub-dependencies: app.js, services.js, controllers.js.
  • app.js file loads and define loads angular.js and creates our Angular app instance.
  • services.js file and controllers.js load with all sub-dependencies.
  • app.init gets called and angular bootstrap kicks in.
  • The page is scanned for directives, ng-controller is found and instantiated via DI. Any referenced modules are instantiated.

Resources

Why use RequireJs?  — RequireJs define API  — RequireJs website

Demo code: link

AngularJs Meetup South London Collection | this article