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.
Related
I am quite new to to angular and most things and concepts are completely new for me.
I am working on a page that have a URL as follows:
http://domain/araneum/page/show/1
Is there any easy way to read the '1' from URL?
What I was able to understand there are two ways:
Read it on backend and create JS variable to be used by angular (not sure if that is the best practices)
Pass the parameter as hash. in my case it is not that convenient, because this page is quite complex already and I wanted to have a separate application for it. Also, there are couple of validations that must happen on backend before page rendering.
Is there any other better approach?
Thanks,
I recommend completing the AngularJs tutorial if you haven't already done so. In particular look at https://docs.angularjs.org/tutorial/step_07
Relevant code for you
phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams',
function($scope, $routeParams) {
$scope.phoneId = $routeParams.phoneId;
}]);
In this example the phoneId will be in place of 1 in your URL.
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
everybody, As you can see the title, i have to confirm my understanding, that
If we have :
angular.module('moduleName', [<Dependencies If any>]);
Then, do we really need this angular.injector, or is it just an another alternative.
If there is any other advantages of using the angular.injector, please let me know.
I have couple of other doubts.
we can use $filter in controller to get the particular filter and use its functions if any.
1. so how to use/call filters in directives.
2. how to call one controller function in another controller, is it possible?
Please Let me know the advantage of using angular.injector over angular.module('moduleName', [<Dependencies If any>]); And when it is good/needed to use it. not the implementaion of angular.injector
I needed it to get some services outside of the angular scope. For example my application is running on some legacy one. To change some parameters in the angular applicaion I needed to access an angular service from javascript outside of the angular. Then I used angular.injector to get the service.
injector = angular.element('#myangularDiv')).injector()
service = injector.get('theService')
Learning angularjs, the curve is steep but I can see that it's going somewhere.
Given the following:
var app = angular.module('theApp',[]);
app.controller('Controller1', function($scope) {
var self=this;
$scope.thing = "hi.";
this.thang = "yo.";
$scope.doIt=function(){
return self.thang;
};
});
thing and doIt() are exposed through $scope, but thang is not:
<body ng-app="theApp">
<div ng-controller="Controller1">
<div>{{thing}}</div>
<div>{{thang}}</div>
<div>{{doIt()}}</div>
</div>
</body>
Is there any way to bind or otherwise expose thang? Or is this. completely pointless inside an ngController?
No problem if it is, just trying to get it straight in my head. I'm getting the idea that and ngController only communicates through $scope (and other ng service objects), they aren't independently accessible to other code; and I see that as a basically good thing, within anjularjs.
But it means you have to go all-in with angularjs; legacy/external code has to be wrapped in angularjs services and stuff in order to communicate across an ngController, would that be a fair statement?
I'm using angularjs 1.2.13, does the behavior change across versions?
Is there any way to bind or otherwise expose thang?
It depends how you want it to be exposed. If you want it to be available in the view; you'll have to put it into the $scope.
If you want to share the value with other controllers, you'll probably want to use a service or to store the value.
Or is this. completely pointless inside an ngController?
I consider variables, or methods, not in the $scope to be similar to a protected variable [or method]. Depending what your building their can be uses for that. I would not consider it pointless.
But it means you have to go all-in with angularjs; legacy/external
code has to be wrapped in angularjs services and stuff in order to
communicate across an ngController, would that be a fair statement?
No, it doesn't mean that. For example, I once wrote an app with a login form, and needed to hash the password before calling a remote service. I just Googled and found a JAvaScript hash library; then imported it into the html page (AKA Used the script tag), and was able to access the hash function from within the controller without doing any other work. This is due to the nature of JavaScript and how browsers work.
However, by doing this I added an external dependency into my controller which would make it difficult to write tests against. If I had wrapped the library in an Angular service, then passed it into the controller I would have built a semi-self-documenting API for the controller that could be tested with known dependencies.
So, you don't have to wrap external services in AngularJS. But, you may want to. As long as you understand the trade offs your making, you can make good decisions for your use case. (Just like any 'best practice').
I'm using angularjs 1.2.13, does the behavior change across versions?
All versions of Angular I've used have the same "Controller / Scope / Dependency Injection" approach.
The ng-controller tag can put the controller on the scope. These are equivalent:
<body ng-app="theApp">
<div ng-controller="Controller1 as c">
<div>{{thing}}</div>
<div>{{c.thang}}</div>
<div>{{doIt()}}</div>
</div>
</body>
And:
app.controller('Controller1', function($scope) {
var self=this;
$scope.thing = "hi.";
$scope.c = this;
this.thang = "yo.";
$scope.doIt=function(){
return self.thang;
};
});
Personally I think putting the name in the tag usually makes more sense as the template reads better.
Remember you can also access controllers which aren't on $scope from the link function of a directive. When you do that you refer to the name you gave the controller when you registered it, Controller1 in this case. See the require attribute here: http://docs.angularjs.org/guide/directive
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.