Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I correctly split angularjs module controllers/services/etc into their own files?

Tags:

angularjs

I've seen some projects keep all the "pieces" (controllers/services/directives) to a module in one file. angular-app does it like that.

example:

angular.module('myModule', ['depA', 'depB'])
  .controller('MyController', function() {})
  .service('myService', function() {});

However I've worked on teams in the past on large angular projects where individual controllers/services/directives were kept in their own files. I like the idea of keeping them in their own files to keep the files small among other reasons. The problem now is that I'm the one in charge of getting the beginning pieces and build process put together. All I had to do before was write application code and follow the standard on those projects.

In order to have separate files properly, I believe I would have to have one main module file.

example:

// file 1
angular.module('myModule', ['depA', 'depB']);

// file 2
angular.module('myModule')
  .controller('MyController', function() {});

So my question is, what file loading order do I need to make sure happens? Do I only need to make sure that the main module file (file 1) is loaded before file 2?

That seems odd to me. If there was also a service file attached to the previously mentioned module and the controller file 2 was already loaded, but the service file wasn't yet, isn't it possible that angular could invoke that controller file and then eventually cause things to get out of whack?

Also, if you think I'm handling this the wrong way I would love to hear your suggestions.

like image 962
Mike Haas Avatar asked Jun 06 '14 23:06

Mike Haas


2 Answers

Module Load Order

Just make sure that when you register a new module, by the time your application bootstraps, it's module dependencies should have already been loaded by the browser.

So anytime you do this:

    angular.module('myApp', ['dep1', 'dep2', 'dep3']);

The files with dep1, dep2, and dep3 should have already been loaded by the time your application bootstraps.

If you are using <script> tags and automatic bootstrapping (the angular default) then the order of your <script> tags shouldn't matter. However, if using a library like requirejs make sure that all of your dependencies are loaded before manually bootstrapping.

Additional Considerations

As long as your modules are loaded in the correct order, then..

  • There is no need to worry about the order of controllers, directives, services, factories, providers, constants, or values

  • The order of run blocks may be important only as they relate to other run blocks since they are executed in the order in which they are registered (within a specific module).

  • The order of config blocks may be important only as they relate to other config blocks since they are executed in the order in which they are registered (within a specific module).

In regards to the prior 2 points, the order of dependencies (for example ['dep1', 'dep2', 'dep3'] vs ['dep2', 'dep3', 'dep1']) will also effect the order of execution of run blocks and config blocks. Angular will traverse the dependency tree twice and execute, in order, all config blocks followed by all run blocks.

Angular uses a post-order traversal to initialize modules and their associated config and run blocks. So if we represent our module dependencies as a tree:

module tree

The order of traversal is ACEDBHIGF

like image 98
Gil Birman Avatar answered Nov 18 '22 04:11

Gil Birman


What I do on my projects, is keep everything separate in the developing environment, but then compile things down via gulp.js (grunt should work as well). That's a separate subject though, but here's an example of how to keep your angular code in different files.

The main file (must be loaded first) could be as follows. We will define our module, controllers, directives, repositories, or whatever else. Let's call it app.js:

// AngularJS Application File

var example = angular.module(
    // ngApp name
    'example',

    // Default Dependencies
    [
        'exampleControllers',
        'exampleRepositories',
        'exampleDirectives'
    ]
);

var exampleControllers = angular.module('exampleControllers', []);
var exampleRepositories = angular.module('exampleRepositories', []);
var exampleDirectives = angular.module('exampleDirectives', []);

Now, we can access this exampleControllers, exampleRepositories, and exampleDirectives from within any javascript file that follows.

controllers.js file.

exampleControllers
  // Main Controller
  .controller('MainController',
    [
      '$scope',
      '$log',
      function ($scope, $log) {
        $scope.hello = 'Hello World';
      }
    ]
  )
  // Sub Page Controller
  .controller('SubPageController',
    [
      '$scope',
      'someService',
      '$log',
      function ($scope, sService, $log) {
        $log.info($scope.hello);
      }
    ]
  );

anothercontroller.js file:

exampleControllers
  // Another Controller
  .controller('AnotherController',
    [
      '$scope',
      '$log',
      function ($scope, $log) {
        $scope.helloagain = 'Hello World, from another controller';
      }
    ]
  )

And so forth.. Just make sure your app.js file gets loaded first so the example<whatever> variables are available.

I would definitely read up on gulp.js (http://gulpjs.com/). It's pretty awesome for automating work flows.

like image 31
Verron Knowles Avatar answered Nov 18 '22 04:11

Verron Knowles