19

I have an Angular application. Its working good, but as my application is getting bigger I'm worried about the large number of dependencies that I have to inject in each controller.

for example

app.controller('viewapps',[
    '$scope','Appfactory','Menu','$timeout','filterFilter','Notice', '$routeParams', 
    function($scope,Appfactory,Menu,$timeout,filterFilter,Notice,$routeParams) {
        //controller code..    
}])

I am sure that the list of dependencies are going to increase in future. Am I doing something wrong here? Is this the right approach? What is the best way to effectively handle this?

4 Answers 4

12

It's hard to be specific without an exact use case, or seeing the exact code in your controller, but it looks like your controller might be doing too much (or might end up doing too much as you add things later). 3 things you can do:

  • Delegate more of the logic to service(s) that are injected in.

  • Separate out into different controllers, so each only has (just about) 1 responsibility.

  • Separate out into directives, each with their own controllers and templates, and allow options to be passed in, and output given out, via attributes and the scope option of the directive. This is often my preferred option, as you end up building a suite of reusable components, each with a mini-API.

    It is fine for directives to be used like this, at least in my opinion. They aren't just for handling raw Javascript events, or accessing the DOM directly.

Sign up to request clarification or add additional context in comments.

2 Comments

i had a factory for every DB table.In one controller i needed to query out 6 table and i had to inject 6 factories+$location+$scope. which was a bit too much. Now i split that into different controllers getting specific data. I guess that is the best way... i think your point number 2 is what should be done.
I dont think this is the solution to what is asked, but an alternative.
7

I've been playing with the idea of bundling services based on controllers.

So in your example you'd refactor your; AppFactory, Menu, filterFilter and Notice services into a single service e.g. ViewAppsServices.

Then you'd use your services like ViewAppsServices.AppFactory.yourFunction().

As I see it that way you can at least shift your injections into another file cleaning your controller up a bit.

I think readability would suffer a bit since another developer would then have to look at bundles rather than the controller itself.

Here's a JSFiddle I put together to demonstrate how it would work; this is how I'd imagine yours would work.

.service('ViewAppsServices', ['AppFactory', 'Menu', 'filterFilter', 'Notice', 
function (AppFactory, Menu, filterFilter, Notice) {
    return {
        AppFactory: AppFactory,
        Menu: Menu,
        filterFilter: filterFilter,
        Notice: Notice
    };
} ])

1 Comment

I suppose this will make my controller heavy.. since sometime I don't need all of the things.
1

Try to move as much logic as possible to services, even just make controller methods act as "routing - passing through" methods . After time you will see it very usefull if you will want to use similar methods in other controllers/directives. Anyway, 7 injections is in my opinion not much :)

(edit: see the comment of Matt Way below) Also, a tip - in newer versions of Angular you don't have to write this array, just:

app.controller('viewapps', function($scope,Appfactory,Menu, $timeout,filterFilter,Notice,$routeParams){
   //controller code..    
}])

2 Comments

You have never had to, but the array is used so that you can do things like safely minify your angular code. It is best practice to always use the array labelling.
IMO the array notation is best left to a build step which can insert it. To me, best practice is to not repeat yourself, and leave that burden to the machines. See github.com/btford/ngmin
-3

My approach is to use $injector, when there are lots of dependencies:

app.controller('viewapps', ['$scope','$injector',function($scope,$injector){                               
    var Appfactory = $injector.get('Appfactory');
    var Menu = $injector.get('Menu'); 
    //etc...
}]);

The advantages:

  • Code can be minified and obfuscated safely
  • You don't need to count the index of the dependency, when you declare dependency as a function's parameter

12 Comments

There are tools, like github.com/btford/ngmin that pre-minify Angular, so you can still write the functions the "nice" way, and have the code ultimately minified. Also, could this be essentially masking long parameter lists, which are usually recommended to be avoided? stackoverflow.com/a/175035/1319998
-1 for the approach :) It beats one of the main benefits of DI. Each resource should be explicit about its dependencies. Using the $injector obfuscates the actual dependencies of the resource (in this case controller) and kills maintainability. (Beware of the pschycopath thatwill end up maintainng your code and knos where you live. He ain't be happy at all...)
The given solution with the $injector is an implementation of the Service Locator pattern. This is an anti-pattern (in Javascript as well) and should be avoided. Besides, you now hide the real cause which is a Single Responsibility Principle violation.
@Steven Your link about the anti-pattern is not applicable for the Javascript.In any case, browser interprets Javascript by runtime*(there is no *compile-time things),and it does not metter you inject the services as a function's parameter or by using $injector. It's almost the same.I assume, that you are not familiar with Javascript and especially with AngularJS. I am aware of Single Responsible Principle as well, but I don't know why do you mentioned about it in here. Your comment is very generic and out of the question's context.
@Engineer I can see why the point on SRP would be in context: the long argument list, that the OP suggests will get even longer, suggests that the controller will be interacting with all of the injected dependencies. This in turn suggests the controller has many responsibilities.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.