'Stand Alone' Controllers VS modular controllers in angularJS - angularjs

I am new to angularJS. I have been reading many code examples and I often see controllers defined as:
function MyController($scope) {
//code here
};
I however am using the method below to define my controller, as I wasn't aware there was any other way to do it.
angular.module("csApp.controllers", [])
.controller("main", function ($scope) {
//code here
};
How does the first method work? Is there some sort of naming convention I am missing here?
Are people using the first method simply adding these functions as global variables by placing them in in script files after angular loads?
How would you connect a global variable to a route if the controller is not registered with angularJS?
Thanks!

The AngularJS Dependency Injection framework can always find controller constructor function in global scope as they are global by nature. Even the ng-controller directive has this in its documentation
Name of a globally accessible constructor function or an expression
that on the current scope evaluates to a constructor function.
When using $routeProvider you can provide the route definition a Controller class or a quoted controller name which has been registered using the module api. These two are valid
route :{controller:MainCtrl,...}
route :{controller:'main',...}
The module based approach is preferable because it stops one from polluting the JS global namespace.

You just need to initialize your module, then you can declare your controllers with the two methods.
The first method make it easier and more readable when you have for instance 5 controllers, or if you want to split them in differents files. But they do the same job. All you need to do is keeping track your controller name.
function MainCtrl($scope) {
// do your stuff
}
<!-- Using the function name here -->
<ANY ng-controller="MainCtrl">
<!-- your HTML data -->
</ANY>
More info in the API Doc.

Related

Divide long controller into small controllers in Angular Js

I am working on complex application and every controller has more than 2000 lines.
Can anyone suggest to break the codes into small controllers and used as a dependency on main controller.
Use multiple controller to handle the task in your page.If you are using long controller you can split the definition to multiple files by passing the scope to another method and then define the rest of methods there.
In the first file:
app.controller('CtrlA', function($scope){
app.expandControllerA($scope);
});
In the second file
app.expandControllerA = function($scope)
{
}
You can pass any variable or dependencies to expandControllerA function.

Pure Controller objects

In AngularJS, a Controller itself is an object defined by a Javascript constructor function and this constructor function is a callback to .controller method.
var myapp=angular.module('scopeExample', []);
myapp.controller('MyController',function MyController($scope){
$scope.name="john";
this.num=700;
});
In the above example, MyController is the constructor function which creates the Controller object with one property (num). I have three queries upon that:
Actually, what is the use of the Controller object in that case?
Does it have some more properties not visible and is it accessible from outside Angular?
How it is interconnected to its scope which in turn is another object?
I came upon the following queries because of the controller as syntax which creates a controller object that is a property of controller's scope and therefore easily accessible, e.g.
<div ng-app="scopeExample" ng-controller="MyController as ctrl">
<input id="box" ng-model="ctrl.num"> equals {{ ctrl.num }}
</div>
<script>
angular.module('scopeExample', [])
.controller('MyController', [function () {
this.num=12;
}]);
</script>
var x=angular.element('#box').scope().ctrl; //x is the controller object itself
1.a. What is the use of the Controller object in that case?
There is nothing special about this example, angular is an MVC framework(or any other buzz word you wish to use that describes almost the same thing), the controller's responsibility is to response to view events, update the model accordingly and execute business logic tasks (you can choose where to actually implement the logic, wheres in the controller itself or use services).
Of course that in this example the controller is pretty useless, because you have no logic, and only 2 proprieties.
1.b. Specking of ctrl-as syntax, in your example you injected 'scope' into the controller and added property ($scope.name), when you're using controller as it is recommended for you to avoid using scope unless you are obligated to do so. (e.g. $watch, parent...)
2.a. Does it have some more properties not visible?
No it doesn't have any invisible properties, you can check it easily by your self with the following code:
.controller('MyController', function () {
window.DoesThisControllerHaveInvisibleProps = this;
});
2.b. is it accessible from outside Angular?
I'm not sure that I fully understood what you've meant with "outside Angular", if so here is an example that the controller obj can be accessible from "outside":
class MyController {
static foo() {
console.log('hello!');
}
}
myapp.controller('MyController', MyController);
// maybe somewhere else in that module
MyController.foo();
3.How it is interconnected to its scope which in turn is another object?
As you said, when using controller as syntax angular is initializing the controller and put it on the $scope so it will be accessible in the template.
$scope is just an unnecessary glow and you should avoid using it. my way of seeing it is like it was angular implantation details, when migrating to ng-2 you will see that there is no more scope.
If you're interested in more detailed info about how exactly $scope and controllers in angular are working I suggest you have a look at

Run an AngularJS method on page load

I have a custom scope method within a Controller, and when a custom directive loads, I want to run a method inside the defined controller. I've seen a lot of options, but which one could be referenced inside a template via an ng-* call? Otherwise, what are the best options?
Since the controller is instantiated when the directive is loaded, any method called in your controller will be called on page load. In my code it is often something like
angular.module('app')
.controller('controllerName', ctrl);
function ctrl() {
/*--------Initialize--------*/
someMethod()
}
If you are on angular 1.5 already and can use the new component way to build your custom directive, you could use the newly introduced $onInit method instead of polluting the constructor, that should only initalize the object itself.
For details, please see this blogpost: https://toddmotto.com/on-init-require-object-syntax-angular-component/

Instantiating a controller dynamically from a string and attaching it to an element

I'm writing code that lets me create dialogs that have some shared elements (e.g. cancel button, ok button, title) but you can also embed your own template and controller to customise it more. When you create the dialog, you specify the template and controller you want in "template" and "controller" field of a dialog "object" which is passed on to the primary controller for handling dialogs. The dialog controller now needs to embed the template and instantiate the named controller to control the template elements.
The template code I'm trying to use for this part is this:
<ng-include ng-controller="dialog.controller" src="dialog.template">
If I remove the controller part, the template appears properly. The controller part generates this error:
"Argument 'dialog.controller' is not a function, got string"
How do I instantiate the controller?
Edit: As an example, with the Angular UI modal library you can do this to create a controller:
var modalInstance = $modal.open({
templateUrl: 'dialog_form.html',
controller: 'DialogFormController',
resolve: {
options: function() {
return dialog;
}
}
});
Where the controller field is the name of one of your controllers. How can I copy this functionality to specify my controller with a string instead of a function?
Angular Controllers are functions, and when you specify ng-controller, Angular will call that function and treat the return result of it as the controller object. That's why controller definitions are done as function-type constructors.
But when this happens there's an additional piece of magic - Angular has a controller Provider that maintains a registry of known controllers, for a variety of reasons. (For instance, it knows what injections they need.) You can't just define a global function and hope it gets called.
If you want to do this, see the ngController documentation which describes this option:
From https://docs.angularjs.org/api/ng/directive/ngController:
If the current $controllerProvider is configured to use globals (via
$controllerProvider.allowGlobals()), this may also be the name of a
globally accessible constructor function (not recommended).
You would use something like this if you wanted the functions supplied to you to be in a global variable, although as noted above it's not recommended.
ngController can also take an expression. In that case it will look for dialog to be a scope variable in the parent controller where this is used, so in there you would need something like:
$scope.dialog.controller = function() { /* ... */ };
This second technique is less useful if you want to make a generic library, but there are ways around it. For instance, you might have your developers create a dialog collection in $scope or $rootScope:
$rootScope.myDialogs['dialog1']['controller'] = function() { };
and then use this in your template like:
<ng-include ng-controller="myDialogs.dialog1.controller" src="myDialogs.dialog1.template">
Finally, you could implement your own ngInclude directive that just did both of those things together from a single argument ('dialog1'). AngularJS Directives give you incredible control over the templates and controllers used to run them.

Add existing JS object to Angular app as a dependency

I'm new to Angular and trying to figure out how to inject some external objects into Angular.
I have a JS script defining a global Payment object with some methods on it. I'd like to somehow import it (the Payment object) into an Angular service (from what I understood the service would be the place to that). How exactly does one go about that?
What I'd like to achieve in the end would be something like:
app.controller("myController", [PaymentService, function (payment) {....}]);
This would work :
app.factory('PaymentService',['$window', function($window){
return $window.Payment;
}]);
Using a factory is an occasion to add additional behavior, for example adding methods or checking that the global object is defined.
You can declare it either as a value:
angular.module('foo').value('PaymentService',window.Payment);
or as a constant:
angular.constant('foo').value('PaymentService',window.Payment);

Resources