AngularJS seed: putting JavaScript into separate files (app.js, controllers.js, directives.js, filters.js, services.js)-ThrowExceptions

Exception or error:

I’m using the angular-seed template to structure my application. Initially I put all my JavaScript code into a single file, main.js. This file contained my module declaration, controllers, directives, filters, and services. The application works fine like this, but I’m worried about scalability and maintainability as my application becomes more complex. I noticed that the angular-seed template has separate files for each of these, so I’ve attempted to distribute my code from the single main.js file into each of the other files mentioned in the title to this question and found in the app/js directory of the angular-seed template.

My question is: how do I manage the dependencies to get the application to work? The existing documentation found here isn’t very clear in this regard since each of the examples given shows a single JavaScript source file.

An example of what I have is:

app.js

angular.module('myApp', 
    ['myApp.filters',
     'myApp.services',
     'myApp.controllers']);

controllers.js

angular.module('myApp.controllers', []).
    controller('AppCtrl', [function ($scope, $http, $filter, MyService) {

        $scope.myService = MyService; // found in services.js

        // other functions...
    }
]);

filters.js

angular.module('myApp.filters', []).
    filter('myFilter', [function (MyService) {
        return function(value) {
            if (MyService.data) { // test to ensure service is loaded
                for (var i = 0; i < MyService.data.length; i++) {
                    // code to return appropriate value from MyService
                }
            }
        }
    }]
);

services.js

angular.module('myApp.services', []).
    factory('MyService', function($http) {
        var MyService = {};
        $http.get('resources/data.json').success(function(response) {
            MyService.data = response;
        });
        return MyService;
    }
);

main.js

/* This is the single file I want to separate into the others */
var myApp = angular.module('myApp'), []);

myApp.factory('MyService', function($http) {
    // same code as in services.js
}

myApp.filter('myFilter', function(MyService) {
    // same code as in filters.js
}

function AppCtrl ($scope, $http, $filter, MyService) {
    // same code as in app.js
}

How do I manage the dependencies?

Thanks in advance.

How to solve:

The problem is caused from you “redeclaring” your application module in all your separate files.

This is what the app module declaration (not sure declaration is the right term) looks like:

angular.module('myApp', []).controller( //...

This is what assignment (not sure if assignment is the right term either) to your application module looks like:

angular.module('myApp').controller( //...

Notice the lack of square brackets.

So, the former version, one with the square brackets, should only be used once, usually in your app.js or main.js. All other associated files — controllers, directives, filters … — should use the latter version, the one without the square brackets.

I hope that makes sense. Cheers!

###

If you’re wanting to put your different parts of your application (filters, services, controllers) in different physical files, there are two things you have to do:

  1. Declare those namespaces (for lack of a better term) in your app.js or in each file;
  2. Refer to those namespaces in each of the files.

So, your app.js would look like this:

angular.module('myApp', ['external-dependency-1', 'myApp.services', 'myApp.controllers'])
.run(function() {
   //...

})
.config(function() {
  //...
});

And in each individual file:

services.js

angular.module('myApp.services', []); //instantiates
angular.module('myApp.services') //gets
.factory('MyService', function() { 
  return {};
});

controllers.js

angular.module('myApp.controllers', []); //instantiates
angular.module('myApp.controllers')      //gets
.controller('MyCtrl', function($scope) {
  //snip...
})
.controller('AccountCtrl', function($scope) {
  //snip...
});

All of this can be combined into one call:

controllers.js

angular.module('myApp.controllers', []) 
.controller('MyCtrl', function($scope) {
 //snip...
});    

The important part is that you shouldn’t redefine angular.module('myApp'); that would cause it to be overwritten when you instantiate your controllers, probably not what you want.

###

You get the error because you didn’t define myApp.services yet. What I did so far is putting all the initial definitions in one file and then use them in another. Like for your example I would put in:

app.js

angular.module('myApp.services', []);

angular.module('myApp', 
    ['myApp.services',
      ...]);

That should get rid of the error, though I think you should have a read on the article Eduard Gamonal mentioned in one of the comments.

Leave a Reply

Your email address will not be published. Required fields are marked *