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?
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.
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
};
} ])
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..
}])
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
Related
.factory("user", userService);
function userService($q, $http) {
function User (){
//....
}
return User;
}
or
.factory("User", ["$q", "$http", function ($q, $http) {
var User = {
//....
}
return User;
}])
I often see both depending of the situation (or rather depending of the author), but I've been wondering for quite a long time now (since I've begun learning Angular), what makes it different, and if I can use one or the other without changing anything. I usually use the first one and following the logic because I find it easier, and because I'm confused with the second one. I may have made mistakes but that's why Im asking for some help. Thanks !
The second code snippet in your question is the one that I'd recommend you to use for all your angularjs services.
Angular framework offers Dependency Injection (DI) feature out of the box that can be used when defining components such as services, directives, filters, animations or when providing run and config blocks for a module.
If you define the dependencies without using an array of string in your angular app, then you are doing it wrong. This way of registering the dependencies will work well for non minified version of the JavaScript source file.
But if you intend to minify the files for production, which everyone must, then all those (dependency) arguments will be changed to something really random which angular will not be able to map to any registered component. So ultimately, an error will be thrown by the framework.
To avoid this mistake, one can just make sure to always use an array of type string to instruct the dependencies. Read this in more detail. If you are your own then you can maybe keep this tip in mind. However, if working in a team, it is good to configure this using the options below so that everyone in the team follows this. If not, then they will encounter an error.
I'd recommend you to use strict DI mode.
How to enable strict mode?
This mode can be enabled using two options as mentioned below.
Option-1:
<div ng-app="myApp" ng-strict-di>
<!-- your app here -->
</div>
Option-2:
angular.bootstrap(document, ['myApp'], {
strictDi: true
});
Learn why is strict DI mode good for your AngularJS app in my blog post.
The first form will not work with minification. The second form is required when minification is used. The reason for this is that the AngularJS injector uses the function parameter names to resolve the $q and $http dependencies in the first form. If the function parameter names are changed (e.g., by minification), that will fail. The second form relies on the strings "$q" and "$http", which will not be changed by minification.
This is discussed in step 7 of the AngularJS tutorial.
I am New to learn a Angular Javascript. Can anyone gave me the knowledge of Dependency Injection with Its Demo Example. So That I did learn from there. No Good and clear link I have found from Googling.
Dependency
injection is a design pattern that allows for the removal of hard-coded dependencies, thus making
it possible to remove or change them at run time.
In general, there are only three ways an object can get a hold of its dependencies:
We can create it internally to the dependent.
We can look it up or refer to it as a global variable.
We can pass it in where it’s needed.
With dependency injection, we’re tackling the third way.We dont follow the first 2 ways because a good programmer never dirty the global scope and it will be difficult for the isolation of the code.
This ability to modify dependencies at run time allows us to create isolated environments that are
ideal for testing. We can replace real objects in production environments with mocked ones for
testing environments.
For instance,let us consider this simple app that declares a single module and a single controller, like so:
angular.module('myApp', [])
.factory('greeter', function() {
return {
greet: function(msg) { alert(msg); }
}
})
.controller('MyController',
function($scope, greeter) {
$scope.sayHello = function() {
greeter.greet("Hello!");
};
});
At run time, when Angular instantiates the instance of our module, it looks up the greeter and simply
passes it in naturally.
Nowhere in the above example did we describe how to find the greeter; it simply works, as the
injector takes care of finding and loading it for us.
For further reference please visit Angularjs Modularization and Dependency injection which can help you get a better understanding.
For debugging and developing I use an area outside of the ng-view showing what I just want to see. It works fine1, but I had to create both a service and a controller for it. My problem is that dividing the work between them is pretty confusing, so I'd like to get rid of one of them.
I don't mind putting the DebugCtrl in the $rootScope or letting the DebugSvc control a $scope (it's hacky, but it's just for hacking, so what?), but for the former, I'd need to make the controller to a singleton and concerning the latter, I have no idea how to get the $scope.
I'm aware about controllers not being singletons. They can't be, as there may be many independent areas controlled by different instances of the same controller. But in my case, I know I need only a single instance. Given the comments, I guess, I need both, but I also need a clear criteria how to divide the work between them.
1 Of course I use the debugger and logging to console, too, but such a debugging playground complements them nicely. It also has buttons for filling forms by debug data, periodical css reloading, etc.
app.factory('controllerSingleton', function () {
return { ... };
});
app.controller('SomeController', function (controllerSingleton) {
return controllerSingleton;
});
While the controller is used with controllerAs syntax in this manner, controller instance is a singleton:
<p ng-controller="SomeController as some"><input ng-model="some.value"></p>
<p ng-controller="SomeController as awesome">{{ awesome.value }}</p>
Obviously, this won't work when scope properties are assigned directly to $scope object, which is unique for each ng-controller directive, and this behaviour shouldn't be changed.
I have an existing angular project that has something really weird with the controller. It looks like the following.
app.controller('AppController', ['$scope', function ($scope) {
var app = app_application;
angular.extend($scope, app);
$scope.itTransports = app.state.itTransports;
}]);
I have a proof of concept for something I am trying to do on this fiddle and an attempt to mix the above controller and my concept in this fiddle but I cant seem to get it to work. I think it is something to do with the weird way the above controller works but I cant break it too badly and cant talk to the previous developer. I would think that if a combination cant be done then I would need some way for one controller to call another one but I want to make sure before I go down that path.
Edit: My main goal is to add functionality to check if the cookie exists. I am trying to do this in the same controller just for simplicity sake, but like I said before I am not adding a new one.
If you have some common functionality that you want to access from multiple controllers (e.g. checking if a cookie exists) then you should put that functionality into a service and inject that service into both controllers.
I have a very small number of functions that I need to use like this:
data-ng-disabled="_isEmpty(grid.view) || view != 'preview'"
What I did was:
$scope._isEmpty = _.isEmpty;
so that the _isEmpty is actually the lodash function.
Is this a reasonable thing to do? Also if so then where would be a good place for me
to code the above line? Should I code that in my appController. Also should I attach
the ._isEmpty to $scope or $rootscope? I have heard people talking about making a service and then injecting this. But for a few lines of code this seems overkill.
It all depends on where this code is required. If it is heavily reliant on, or required by a particular data object or view, then it most likely belongs in a controller. If inside a controller, $scope should be used by any value you want to reference in a view.
If however, you are writing generic functions used throughout your application, then they should be put in something like a service, and injected where required. Most of the time if you find yourself using $rootScope, the code should probably be in a service. Services aren't really overkill, as you can see below:
angular.module('myapp.services.something', [])
.factory('myService', [function () {
return {
myFunc: function (someArg) {
console.log(someArg);
}
};
}]);
You could put any number of generic helper functions for example in a service like this, and inject them into any controller that requires their use.
Though generally not recommended, I could see this kind of problem solved with putting the functions into the rootscope. Then putting the line $scope._isEmpty = _.isEmpty; in every controller would not be necessary anymore. A far better way for me would be to recode the utility functions into directives, even if involves some coding. Another way to solve the problem is to use services.