Referencing Controllers - angularjs

I was not able to find in documentation if it is possible to reference a controller using a similar syntax to the one used to reference modules:
angular.module('App').controller('Ctrl');
That does not seem to work!
This is in angular 1.2

Here is link to documentation http://docs.angularjs.org/guide/controller
In paragraph with title "Adding Behavior to a Scope Object" you can see example how to use syntax like you gave above.
JS
var myApp = angular.module('myApp',[]);
myApp.controller('DoubleCtrl', ['$scope', function($scope) {
$scope.double = function(value) { return value * 2; };
}]);
HTML
<body ng-app="myApp">
<div ng-controller="DoubleCtrl">
Two times <input ng-model="num"> equals {{ double(num) }}
</div>
</body>

I don't think there are a lot of reasons to be creating controllers in services, other than for templating purposes, but of course you can!
You can use the $controller service to create instances of controllers on demand. If the controller requires a $scope, you'll have to pass it as a local: $controller("MyController", { $scope: otherScope.$new() }). AngularJS does the $scope bit for you when a controller is created internally.
See $controller for (slightly) more details.

Related

Confusion between $scope's in controller and its function?

I'm new to UI. I do have confusion between $scope's in AngularJS. Please refer below snippet.
var mainApp = angular.module("mainApp", []);
mainApp.controller(['$scope', function($scope) {
$scope.name = "John";
}]);
So, what's the difference between $scope and function($scope)? Also how can we relate both? Is it required to have $scope parameter? Please explain me with an example. I really appreciate that.
Thanks,
John
1.When you apply Minification of Following Angular JS code:
var mainApp = angular.module("mainApp", []);
mainApp.controller(['$scope','$log', function($scope,$log) {
$scope.name = "John";
$log.log("John");
}]);
Minified Version :
var mainApp=angular.module("mainApp",
[]);mainApp.controller(["$scope","$log",function(n,o)
{n.name="John",o.log("John")}]);
2.When you apply Minification of Following Angular JS code:
var mainApp = angular.module("mainApp", []);
mainApp.controller(function($scope,$log) {
$scope.name = "John";
$log.log("John");
});
Minified Version :
var mainApp=angular.module("mainApp",[]);mainApp.controller(function(n,a)
{n.name="John",a.log("John")});
3.When you apply Minification of Following Angular JS code:
var mainApp = angular.module("mainApp", []);
mainApp.controller(function($log,$scope) {
$scope.name = "John";
$log.log("John");
});
Minified Version :
var mainApp=angular.module("mainApp",[]);mainApp.controller(function(n,a)
{n.name="John",a.log("John")});
You will Notice in Ex-2 and Ex-3 that you have interchanged the Dependency place of $scope and $log then also your minified version is the same ,this will give you dependency Injection error ,so we place a String value as String Value can't be minified as you can see in Ex-1.
It is not required to have $scope each time you define your controller but $scope provides important functionality like binding the HTML (view) and the JavaScript (controller). .
https://docs.angularjs.org/guide/scope
what's the difference between $scope and function($scope)?
When you do
mainApp
.controller(
['$scope', //line 1
function($scope) //line 2
{
}
]);
In line 1 it refers to $scope, which is an object that refers to the application model
In line 2 it is the variable (conveniently called $scope too) in which the (mentioned above) $scope object is injected. This variable can have any other name, $scope is used as a way to keep a suggestive reference through the whole code.
For instance, your example would work too if I change its name to myFunnyScope like this:
var mainApp = angular.module("mainApp", []);
mainApp.controller(['$scope', function(myFunnyScope) {
myFunnyScope.name = "John";
}]);
Also how can we relate both?
Taking as reference my previously posted snippet, you can tell the $scope object is being injected in the myFunnyScope variable, it means you use myFunnyScope as if it were $scope itself.
Is it required to have $scope parameter?
As long as you need to get access to all benefits provided by the mentioned $scope object, when you do minification it is required to inject the object ([$scope, ...) into the holder (function($scope) { ...) in order to not get the AngularJS application broken. Otherwise, no, you don't need to inject the object, but then you have to explicitly call it $scope in the function parameter so AngularJS knows it has to inject the $scope object inside it. This rule applies not only to $scope, but to all other AngularJS related services, factories, etc such as $timeout, $window$, $location, etc.
You might want to read about the AngularJS injection mechanism and consider using the controller as syntax for reasons explained here if you do not want to use $scope directly.

"Partial Template" Error: Argument 'MyController' is not a function, got undefined

I am getting the above error within a partial template loaded into the main html. When I declare the controller as global it works (MyController1), also when I declare the controller directly within "app.controllers" it works, but when I declare the controller (MyController) as part of the partial template the above error appears. Any help?
Code
<div ng-controller='MyController1'>
<span ng-bind="mydesc"></span>
</div>
<script type="text/javascript">
function MyController1($scope) {
$scope.mydesc = "Direct Global Definition";
console.log('in Direct');
}
angular.module('app.controllers').controller('MyController',['$scope',function($scope) {
$scope.mydesc = "Defined as part of Controller Inline";
}]);
</script>
The above code works, but when I change ng-controller="MyController1" to ng-controller="MyController", the error appears.
I don't want to use global functions and I can't add every partial controller to "app.controllers".
Looks, like you use angular 1.3 version.
In that version global functions as controllers were disabled according to release notes, but still, you're able to use them. All you need to do is to configure controller provider to allow global methods to be used as controllers.
Here is full working code
<div ng-app="app.controllers" ng-controller="MyController1">
<span ng-bind="mydesc"></span>
</div>
Though it's not recommended to use global methods.
function MyController1($scope) {
$scope.mydesc = "Direct Global Definition";
}
app = angular.module('app.controllers', []);
app.config(['$controllerProvider', function($controllerProvider) {
$controllerProvider.allowGlobals();
}]);
app.controller('MyController', ['$scope', function ($scope) {
$scope.mydesc = "Regular definition";
}]);

I need a clarification about dependencies

What is the difference between:
myApp.controller('GreetingController', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
}]);
And
myApp.controller('GreetingController', function($scope) {
$scope.greeting = 'Hola!';
});
Some of the examples add dependency for scope and some are not.
Thank you.
Both your samples have a scope dependency injected, the difference being the first one uses the array notation which allows you to create custom naming, won't break when minifying, etc... It's the recommended way. For example, this works fine:
myApp.controller('GreetingController', ['$scope', function(myScopeAlias) {
myScopeAlias.greeting = 'Hola!';
}]);
See it in action here:
angular.module('test', [])
.controller('GreetingController', ['$scope', function(myScopeAlias) {
myScopeAlias.greeting = 'Hola!';
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="GreetingController">{{greeting}}</div>
Dependency Annotation
Angular invokes certain functions (like service factories and controllers) via the injector. You need to annotate these functions so that the injector knows what services to inject into the function. There are three ways of annotating your code with service name information:
Using the inline array annotation (preferred)
Using the $inject property annotation
Implicitly from the function parameter names (has caveats)
Read more: https://docs.angularjs.org/guide/di#dependency-annotation
I just want to emphasis one point:
Always using the inline array annotation if you project need to do the Uglification(Most real project need a uglification).
Building minification-safe Angular.js applications

The impact of creating a controller function with and without angular.module().controller() in angular?

In the Angular documentation there are two examples of creating a controller:
function GreetingController($scope) {
$scope.greeting = 'Hola!';
}
and
var myApp = angular.module('myApp',[]);
myApp.controller('GreetingController', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
}]);
Both are used in the markup:
<div ng-controller="GreetingController">
{{ greeting }}
</div>
My question is, what are the advantages of using the angular.module().controller() method?
A controller is basically a function. In the first case you can reuse the function over all your applications(global scope function) and not bind it to one.
The second case actually attaches the controller to an application(application scope), allowing you to pass not only a function but an array that includes strings in case you want to minify your javascript files.

Dynamically loading controllers with their own scopes

I'm having a problem which I'm not sure whether is a down to a limitation of Angular (possibly) or a limitation of my knowledge of Angular (probably).
I am trying to take an array of controllers, and dynamically create/load them. I have a prototype working to the point where the controllers run and the root scope can be accessed, but I cannot dynamically attach ng-controller to divs in order to encapsulate the controllers into their own local scopes.
The problem is that the templates are bound to the root scope but not to their own scopes.
My example will hopefully explain my quandary better.
JSFiddle: http://jsfiddle.net/PT5BG/22/ (last update 16:30 BST)
It may not make sense why I am doing it this way, but I have pulled this concept out of a larger system I am creating. In case you have other suggestions, these are the laws by which I am bound:
Controllers cannot be hard-coded, they must be built from an array
Scopes cannot be shared between controllers, they must have their own scopes
The docs on AngularJS are not exactly comprehensive so I'm hoping someone here can help!
You can just pass the controller name through and use the $controller service and pass the locals through to it. You'll need some sort of ModuleCtrl thing to co-ordinate all this. Here is a basic example that does what you want.
http://jsfiddle.net/PT5BG/62/
angular.module('app', [])
.controller('AppCtrl', function ($scope, $controller) {
$scope.modules = [
{ name: "Foo", controller: "FooCtrl" },
{ name: "Bar", controller: "BarCtrl" }]
})
.controller('ModuleCtrl', function ($scope, $rootScope, $controller) {
$controller($scope.module.controller, { $rootScope: $rootScope, $scope: $scope });
})
.controller('FooCtrl', function ($rootScope, $scope) {
$rootScope.rootMessage = "I am foo";
$scope.localMessage = "I am foo";
console.log("Foo here");
})
.controller('BarCtrl', function ($rootScope, $scope) {
$rootScope.rootMessage = "I am bar";
$scope.localMessage = "I am bar";
console.log("Bar here");
});
The way I finally got around this was quite simple, it was just a case of working it out.
So I have a list of modules, that I get from an API, and I want to instantiate them. I include the template file by building the path via convention, like so:
<!-- the ng-repeat part of the code -->
<div ng-repeat="module in modules">
<ng-include src="module.name + '.tpl.html'"></ng-include>
</div>
In each of the modules template files, I then declare the ng-controller and I declare a method to fire in ng-init. As the template is still within the ng-repeat loop, it has access to module, which has the data we want to pass to the child controller. ng-init runs on the local scope, so we pass in the module object:
<!-- the template of the module -->
<div ng-controller="ModuleCtrl" ng-init="init(module)">
...
</div>
And then we store it on the local scope and there you go, injected the object.
/* the controller of the module */
.controller('ModuleCtrl', function ($scope) {
$scope.init = function(module) {
this.module = module;
};
// this.module is now available inside the controller
});
It took a bit of hacking but it works perfectly for now.

Resources