How does angular resolve controllers defined in modules? - javascript

Looking at the angular documentation for controller there's something that confuses me. Let's say someone does this:
angular.module('foo').controller('controller1', ['$scope', function($scope) {
});
and:
<div ng-app='app' ng-controller='controller1'>
</div>
How does angular know that 'controller1' resides in module 'foo'?
And furthermore if someone does this in addition:
angular.module('bar').controller('controller1', ['$scope', function($scope) {
});
Which one will angular chose now?

When you declare ng-app here:
<div ng-app='app' ng-controller='controller1'>
</div>
Angular will look for a module definition with the name app. Something like this:
angular.module('app', []); // notice the []
Inside the second parameter [] array, Angular wants the dependent modules. So, in order to include controller1 from foo module, you would do this:
angular.module('app', ['foo']);
And from the bar module:
angular.module('app', ['bar']);
In each of these, there is only a single controller1 named controller.
So, what happens when you register both the foo and bar modules? I would think that the last one wins. So, if you define app to be:
angular.module('app', ['foo', 'bar']);
Then, the bar module's controller1 will overwrite the name controller1 inside the injector.
So, there is no built-in mechanism that allows for the same name to be applied across modules. Because of this, you can employ naming schemes to make sure that the controller is unique:
angular.module('bar').controller('bar.controller1', ['$scope', function($scope) {
});
How does angular know that 'controller1' resides in module 'foo'?
At the time that Angular is resolving controller1, it doesn't know what module it is in. Once the module is a dependent (on the module defined in ng-app), all of the controllers (in all modules) are only resolved off of their names.

Angular doesn't really know where the controller comes from. Your application includes either foo or bar and then controller1 is registered.
If you include both foo and bar controller1 is from whatever module you included last.

Related

Passing a constant value among controllers angularjs

I have a constant value that is common throughout my project, among 2 of my modules- I want to have a design that I would have to only define it in one module and pass on the value to another module. How can I ?-
Module1 is like
var myApp = angular.module('myApp', ['ui.router']);
myApp.constant('constVar', 'http://45.26365.23/mydata/');
and Module2 is like
var Dashboardapp =angular.module('Dashboardapp', ['ui.router']);
Dashboardapp.constant('constVar', 'http://45.26365.23/mydata/');
For the record, the Google internal style guide says "do not define variables on the scope." (It actually explicitly says that). Note that means in particular, but not only, $rootScope (your code would be guaranteed to get kicked back in review if you did that, with very ugly "THIS IS BAD" comments).
Just define it at a higher level then both modules, typically at the app level (Angular 1.x defines a configurable place for constants in the app config API, you may want to look that up, this is useful because it actually enforces the constant). You can also just use a class defined in no module at all (just a top level class that you import and use statically), or you can define another module that you inject (which might be overkill for a few simple constants).
A naive approach would be to define the constant outside the modules:
var myConstant = 'http://45.26365.23/mydata/';
or maybe even better if you have more constants or other general data:
var myConfig = {
myConstant : 'http://45.26365.23/mydata/'
// other data
}
and then call it in the modules:
var myApp = angular.module('myApp', ['ui.router']);
myApp.constant('constVar', myConfig.myConstant);
var Dashboardapp =angular.module('Dashboardapp', ['ui.router']);
Dashboardapp.constant('constVar', myConfig.myConstant);
Other possibility would be to define it in only one module, which would be your main module, and inject it in the other modules:
var myApp = angular.module('myApp', ['ui.router']);
myApp.constant('constVar', 'http://45.26365.23/mydata/');
var Dashboardapp =angular.module('Dashboardapp', ['ui.router', 'myApp']);
Dashboardapp.constant('constVar', myApp.constant);
Instead of the last line you could just call the constant where ever it is needed.
You could always use the 'constant' that Angular comes with ...
import * as angular from 'angular';
export default angular
.module('app.constants.foo', [])
.constant('fooAction', Object.freeze({
name: value
}))
.name;
Then you inject your named constant. Thus it is accessible anywhere in the app (and more importantly immutable (mostly)).

How to define controllers in separate files

Suppose that I have an SPA written via AngularJS 1.x.
It has a single app module defined like this:
var app = angular.module('app', ['ngAlertify', 'ngRoute', 'ui.bootstrap'])
I also have several controllers which are defined in separate *Ctrl.js-files. What is the appropriate way to define them?
I see two options here. The first one is
app.controller('LoginCtrl', function($scope) { /* ... */ });
and the second one is
angular.module('app').controller('LoginCtrl', function($scope) { /* ... */ });
Which one is better and most common-used practice? Is there any downsides of using either of them?
If I understand your question correctly then you wan to know different between
app.controller('LoginCtrl', function($scope) { /* ... */ });
vs
angular.module('app').controller('LoginCtrl', function($scope) { /* ... */ });
In above two in first method app is a global object which you declared somewhere i.e. in app.js like
var app = angular.module('app',[]);
In this case app is a global variable which will be accessible throughout your entire application. which I believe is not a good thing to use global variable
in our application.
In second method we are using global angular object to create a controller so that in this we will not be using global variable. In this case app.js will look like
(function(){
'use strict';
var app = angular.module('app', []);
....
....
....
....
})
In this case app variable will not be available anywhere apart from this file.
So I belive second method is better than first one.
My personal preference is to use app.controller('LoginCtrl', function($scope) { /* ... */ }); as this makes it easier to reuse the controller in another project with little to no changes, without those annoying module not found errors because you forgot to rename the module when reusing the file
I think that depends a bit on the personal style of writing. One thing is that while working with AngularJS 1.x.x you can have different styles of writing code, method stacking etc.
Personally, I prefer app.controller('LoginCtrl', function($scope) { /* ... */ }); mainly because you can easily preview your controller and distinguish it from thge module. Another bonus I see of having a clearly defined separate module is that you can easily check what includes you have ('ngAlertify', 'ngRoute', 'ui.bootstrap').
Most commonly used as far I have seen, even here on SO, is the method that I previously mentioned. Yet again this is something that is more reflective of personal style rather than strong pre-requirements of writing code. I hope that helps to some extend.
None of the above. The purpose of modules is to keep the application modular and not pollute global scope.
You can have var app = ... but this should be done inside IIFE once per file.
Another issue with modules is the precedence. If the application uses angular.module('app') module getter, the files should be loaded in specific order, in order for the module to be defined when it is retrieved in other files. This creates problems if they aren't, for example when they are concatenated in alphabetic order.
The solution is to use one module per file. This makes the application truly modular, independent of file loading order, also benefits testability. See also this answer for how this pattern supposed to work.
You can use module setter and getter methods for implementation of controllers in different file.
Suppose myApp.module.js
angular.module('myApp', []); //Setter method, registring module
In myApp.homeCtrl.js
var myApp = angular.module('myApp'); // getter method, getting the module already registered.
myApp.controller('homeCtrl', [function()]{ })
For more info check this https://toddmotto.com/angular-modules-setters-getters/
The second approach your are taking about is better because it uses the already created module and doesn't create the new module but with the first approach you are using global variable that is not recommended

Why controllers is being created 2 times in my AngularJS + RequireJS application?

I am creating small application called puzometr. It is for educational needs only. I want to create this application using AngularJS. Also, I want to use RequireJS as module system.
I have strange problem. I created my test controller and I got problem: controller initialization fires two times.
Firstly, full code available here on GitHub (wait, don't click me, I will explain everything below).
So, problem is in myCtrl.js file. Here is code of this file:
define(['angular'], function (angular) {
var module = angular.module('main.myModule', []);
module.controller('main.myCtrl', function ($scope) {
console.log($scope.$id);
$scope.bob = function () {
}
})
});
It is included in main/controllers/controllers.js by this:
define(['app', 'main/controllers/myCtrl'], function (app) {
var module = angular.module('main.controllers', ['main.myModule']);
});
This file included in main.js by this code:
angular.module('main', ['ngRoute', 'main.services', 'main.controllers', 'main.directives']);
And main.js is included into app.js:
var app = angular.module('myApp', ['ngRoute', 'main', 'common']);
So, I incidentally noticed, that function definition in myCtrl controller fired two times. I put console.log there and saw this:
Can you please explain me why is this happens? Why controller is being initialised two times?
Also, I have this in ng-inspector:
So one scope is created as child for another scope. Notice, that scope with id 3 has correct controller name.
If you use ng-route to register controllers and bind them with views, then don't add them again using attributes in your html files.

Angular UI-router, controller is undefined

I am kind of new to the AngularJS framework and I am trying to migrate my test project using the standard router to use the UI-router, but I get the following error:
Error: [ng:areq] Argument 'mainCtrl' is not a function, got undefined
What I have done so far is:
Controller:
// mainCtrl.js
angular.module("sm-web")
.controller('mainCtrl',['$scope',
function($scope) {
...
}]);
Router:
angular.module('sm-web', ['ui.router'])
.config(['$stateProvider', '$urlRouterProvider', function( $stateProvider, $urlRouterProvider ) {
$urlRouterProvider.otherwise('root');
$stateProvider
.state('root', {
url: '',
templateUrl: path + 'ng/sm/view/main.html',
controller: 'mainCtrl'
});
}]);
Index:
<body ng-controller="mainCtrl">
<main-menu></main-menu>
<div class="container">
<div ui-view></div>
</div>
</body>
This works when I use the standard router, but not with the UI-router. Does anyone have any idea of what I am doing wrong?
It seems you have an issue w/the order you declare things. For you to declare the module "sm-web" you need to do this:
angular.module('sm-web', ['ui.router']);
Note that the presence of that 2nd array argument is what tells Angular that you're declaring the module (eg. creating a new module). When you leave that 2nd argument out, you're retrieving the module you previously declared.
So with that in mind, look at how it all is coming together in your code:
To declare the controller, you retrieve the module "sm-web" (by leaving off the 2nd array arg).
When configuring the router states, you declare a new module "sm-web". But note that immediately after you declare this new module, you try to register a state with the controller named "mainCtrl" -- but that doesn't exist yet.
You need to create the module somewhere before doing all of the above. After creating the module, then register the controller on the module. Finally, with the controller defined, then you can register the state that uses the controller.
There's too many ways to solve this ordering problem, so I'm not going to suggest anything further. It depends on what files the code lives in and the order you load those files in index.html.
In order to avoid your problem change your code by the following code:
// mainCtrl.js
angular.module("sm-web")
.controller('mainCtrl',['$scope',
function($scope) {
...
}]);

Dependency Injecting an empty module into a controller in Angular

I am trying to dependency inject a module into another—the former is simply an empty module.
angular.module('module1', []);
angular.module('module2', [])
.controller('Module2Ctrl', ['module1', '$scope', function (module1, $scope) {
$scope.expression = 'hello!';
}]);
HTML:
<html ng-app="module2">
<body ng-controller="Module2Ctrl">
<h1>{{expression}}</h1>
</body>
</html>
I'm getting the dreaded Unknown provider: module1Provider <- module1 <- Module2Ctrl message.
What's going on? I believe everything is defined as it should be—though module1 has no definitions, I can't find information anywhere on what would stop this from working.
Plnkr: http://plnkr.co/edit/goMVFRNuPgG6iIpGYI1Y?p=preview
Thanks :-)
You inject providers (such as factories, services, ...), not modules. Remove the module1 injection and it will work. What you're thinking of doing is probably declaring module2 as a module dependency of module1:
angular.module('module1', ['module2']);
and then ng-app="module".
angular.module can not injected inside a controller,Only one angular.module can be injected inside another module.
angular.module('module2', ['module1'])
You should never do that angular. Only angular components are inject-able like service,controller, factory, filter, provider,etc.
For initializing angular on page you could do angular.bootstrap
angular.bootstrap(document,["module2"])

Categories