AngularJS - How to route to a controller in different module - angularjs

I have a question related to modules and routing in angularjs. The requirements are to define all routing configs in one module - lets call this ModuleRtr.
Once the route is triggered, it should call a controller (called TestCtr for example). This controller is defined in another module - let's call it ModuleCtrl.
If I try to do that, I got an exception like:
"Argument TestCtr is not a function, got undefined"
. The reason is that when angular broadcast $routeChangeSuccess event, the listener tries to access the controller (TestCtr) as part of the current module - ModuleRtr. Because it's not there, it throws an error.
If I simply create TestCtr controller in ModuleRtr (the same that has the route in it), then everything works. But I don't want that, I want to have my TestCtr in different module. I also don't want to have route define in ModuleCtrl module.
So, in more straightforward way, my question is: Is it possible a route defined in one module (ModuleRtr) to call a controller defined in another module (ModuleCtrl)?
Something that I forgot to mention...I don't want to bind these 2 modules by any means. That of course includes listing a dependency during module's creation. I have already tried dynamic loading of TestCtr - it didn't solve the problem.
The scenario is: You have 2 angularjs applications (modules). They don't know anything about each other...except one thing - somewhere in a shared/common location, there is an object which follows a particular structure (like a contract). The first module writes data there. Then it runs a common function from the second module (this is actually the question I am asking - how?). Then the second module knows already where to go (it's a contract) what to read and what to do. One way I can do this is to try dynamically generates the string that represents a module dependency when the other module is created. I am not sure if that is a good solution...
Many thanks!

You can use a single module with submodules for each functionality, such as:
angular.module('myApp.home',[]);
angular.module('myApp.routing',[]);
...modules here...
angular.module('myApp', [
'myApp.home',
'myApp.routing'
]);
So you can send a method from myApp.home calling a intermediate method from myApp and this one calling the myApp.routing method.
At least, this is how I see it.

Related

AngularJS and modularisation

AngularJs provides you the possibility to create modules. All fine. It also give you the power to add components to your modules like service, controller, etc...
My only problem with that is that no matter in what module did you define a component, from another module it can be entirely overwritten.
Examples:
app.module('aModule').controller('SimpleController', functino(){...});
app.module('bModule').controller('SimpleController', functino(){...});
If you try to define let's say a state definiction with ui-router, it will just won't work well, since one controller will completely overwrite the one loaded first.
Did you guys met with this problem too or it's just me?
no, that's normal behavior. You can namespace it like 'component.controller' (so do this in the name of the controller, not the module) which helps, other then that is not possible in Angular 1

Add dependency to Angular module after it's been created

Do you guys know if it's possible to add a module dependency after it's been created? Something like that:
// init module in file A
angular.module("myApp", []);
// retrieve module in file B and add new dependencies:
mod = angular.module("myApp");
// now I want to add an 'ngResource' dependency to mod
// ???
EDIT: I understand this may seem a weird question. I am working on a component based app organization and want too see if a subcomponent can add dependencies to it parent component module without defining its own module. Something like that:
app/
components/
|__componentA/
|__app.js // initializes component A module
|__subcomponentA/
|__app.js // want to add subcomponentA dependencies to componentA module from here
My alternative is simply declare all subcomponentA dependencies directly on the componentA module, but from organization point of view, I'd prefer to keep these dependencies inside the subcomponentA directory, so if I later decide to remove the subcomponentA from the app, I don't need to remember to remove its dependencies from the componentA module. I want everything that concerns subcomponentA to be grouped inside the subcomponentA directory. My build script will ensure that componentA code is processed before the subcomponetA is, though.
Thank you to everyone who takes a stab at this.
I use the following method for this and working fine for me.
var app = angular.module("myApp", []);
angular.module("myApp").requires.push('ngResource');
I don't think this is possible. However, I'd love to be proven wrong.
From my experience (and according to the Angular documentation) module dependencies can only be declared when initializing a module. It's worth noting that until the application is bootstrapped, the dependencies aren't completely set. It's not possible to add dependencies to a running application as far as I know, unless there's a way to rebootstrap the entire app, which might have unwanted side effects anyway.
Edit: Actually....I've never tried this, but this actually might be a lot simpler than I originally thought. We could try the following:
File A:
window.myApp_dependencies = []; // Add dependencies to the global scope.
angular.module('myApp', dependencies);
File B:
var mod = angular.module("myApp");
window.myApp_dependencies.push('ngRoute');
This isn't really ideal as you are forced to create a variable on the global scope. It would be possible to do it with modules, though. Note that in this case, the dependencies would only be mutable until the app actually started - so, you could split dependencies across files, but you wouldn't be able to change them at runtime.
I don't know if this works. I'm going to try it out tomorrow, though.
Strange question but still what you trying to achieve is something wrong in prospect of angularjs/SPA/dependency injection
Your use case is something like you wants to use this dependency in a particular module or in one page. Thats why you wants to inject it at one position not the other.
But, doing this would make two different scopes for your application becuase using same name of module if you reinitiallized that module that would be different that the other one which is already declared
say: file A
angular.module("myApp", []);
This is defined and in file B
mod = angular.module("myApp", ['ngResource']);
so this would cause to have two different app with same name in one application and that two app with same name in different files
so its something like to have two different angular module inside on application.
Second option: let have the same module across the application and inject in at one point and in any controller you wants to use this inject that as a argument in that controller.
Hope this help!

Me, AngularJS, and its 3 different ways to specify a controller

I'm confused by these three different ways to specify a controller.
1- I can have an include in the app/index.html file:
<script src="scripts/controller/nav.js"></script>
2- I can have an attribute in a route:
.when('/link/list/', {
templateUrl: 'view/list.html',
controller: 'navController'
})
3- I can have an attribute in a view:
ng-controller="navController"
It's quite a few. I wonder which way to go and when.
Kind Regards,
Stephane Eybert
Your (1) has nothing to do with (2) and (3).
And there are other places where you can bind controllers (e.g. a directive's controller property).
Each way is serves a different purpose, so go with the one that suits your situation.
If you have a directive and want to give it a specific controller, use the Directive Definition Object's controller property.
If you use ngView and want to give each view a specific controller (as is usually the case) use the $routeProviders controller.
If you want to assign a controller to some part of your view (in the main file or in a view or partial) use ngController.
All the above are methods for "binding" a controller to some part of the view (be it a single element or the whole HTML page or anything in between).
Im quite new too but Ill try to explain in a more layman way.
1 For each .js file you have (which may contain one or more controller defined), you need a corresponding entry into the script for #1 there. Its not the controller itself, more like to allow script to recognise that this .js file is part of the set of files to run.
2 is more like specify a state or route, which may or may not use a controller. Its much like saying how one event should lead to another. The controller may be involved in the transitions of the states/routes (ie. responsible from one state, to another) or within a view itself.
3 is for using a controller's functions within a view itself.
I've added comments to one of the answers, but aside from syntax this may is more of a design question. Here is my opinion
Firstly, (1) is irrelevant to the conversation.
(2) is the preferred approach when specifying the controller for the view as it decouples the controller from the view itself. This can be useful when you want to re-use the same view by providing a different controller.
If you find yourself using (3),consider making that area into a directive, since by specifying a controller you are indicating that it requires its own logic.

Setting initial $rootScope defaults don't seem to work

I would like to have few global variables that are UI related (i.e. open menu state). I decided to put these in $rootScope so they're always accessible.
This is the code I've written:
(function (angular) {
angular
.module("App", [])
.run(["$rootScope", function ($rootScope) {
angular.extend($rootScope, {
ui: {
menu: false,
...
}
});
}]);
})(angular);
I've deliberately used angular.extend, to make sure that consecutive manipulations to the same object are retained. And I think it's also more clean and safe than adding several properties to any object one by one.
Problem
Upper code doesn't do anything though. When I run my application and check root scope by calling:
$("body").scope().$root.ui
I get undefined until some property within ui gets manipulated by ng-click directives on my application. Only then my ui gets a reference... But it's still not the one I've defined in the run() function but rather angular generated object property that ng-click directive generated as per expression.
What am I doing wrong?
Resolved - module got overwritten
Ia managed to resolve it myself. Code contained in the upper question isn't sufficient to show the actual problem in my application. The problem was the way I was loading module requirements and file ordering.
I'm loading files in this order:
app.js
routing.js
service.something.js
...
filter.something.js
...
So I thought to add module requirements to my app module in subsequent files (make ti actually modularized). This would make it simple to either include or exclude particular files without any runtime errors. It would also allow loading additional files dynamically as application runs.
The problem with my code was that I've overridden my original module in subsequent files. When I added all module requirements into app.js everything everything started working.
Possible workaround
I can see that I'm not the only person that would like this kind of functionality. Lasy module requirements loading is possible as per this Google groups' post.
What it does is it creates a new injector function
instanceInjector.loadNewModules = function (mods) {
forEach(loadModules(mods), function(fn) { instanceInjector.invoke(fn || noop); });
};
that can later be used by individual modules to add themselves as requirement to the main application module by doing this:
$injector.loadNewModules(["Module1", "Module2", ...]);
Although it would be much better (my opinion) if there was an additional function on Module type called requires() so one could do this instead:
angular.module("MainModule").requires(["AdditionalModule", "OtherModule", ...]);
I think that would make it more concise and easy to use and understand.

Define controllers in app.js Extjs

Here my app.js code :
Ext.Loader.setConfig({
enabled: true
});
Ext.application({
name: 'KP',
appFolder: 'scripts/app',
controllers: [
'login.Login'
],
views: [
'login.Login'
],
launch: function () {
var view = Ext.widget('login')
}
});
If I want to use some others views, controllers, models and stores in my application, should I define them in app.js? (like this : controllers[....all of my controllers.....])
Are there other way to get to work init function in my controllers? Thanks!
There are many ways...
Following some basics first:
All controllers that are listed within the controllers array of the application controller get instantiated at startup (application get initialized with the onReady event. Also the init() and onLaunch() methods of the listed controllers get called. See the linked API for details when this occurs). Now each instantiated controller initialize its stores,views and models (creates getter for all and over that creates instances of each store while overwriting the storeId and append them to the Ext.StoreMgr). Note that each controller will contains his own models, stores and views.
The simplest way to receive a controller that is not listed in the application controller is by using a reference of the application controller and calling getController(name)
It is Important to know that while using that way the receive a controller instance the getter method will not call the init() or onLaunch() method for the invoked controller, it will just try to get the controller or create it. You should also note the API for those methods in these controllers are no longer correct. You need to set an init bool to these controllers and check it on the reference that the getController(name) method hands back to you. If it is undefined/false you call the init() / onLaunch() by yourself and set it after that. I use these technique by myself to reduce intial load for bigger application. I guess you don't really need this for just a handful of controllers.
Update
Due to some changes in the 4.1.x release it is no longer required to init the controller
manually. This is now done for us by the getController method
You can define as many controllers as you want. To implement hierarchy you can define views and stores related to certain controller within it.
For example:
controller/
artists.js (inside: artistsView1.js, artistsView2.js, artistsStore.js)
paintings.js (inside: paintingsView1.js, paintingsStore.js)
All of your views and stores used in controllers would be loaded and initializadduring Applocation load.
The controllers you define in your application are loaded before the application launch() is called. As each controller is loaded its models, views and stores (MVS) are also loaded.
Although you can define the MVSs in your application, I'd recommend that each controller defines its related MVSs, as it is possible for the programmer to load controllers (and their related MVSs) upon request rather than by default. It is also a good practice from reusability point of view (so if you ever to reuse the controller, you know what MVSs come with it).
You may want to include some views in the application if, say, they are used without controllers, like some sort of a custom window you display if there was some error in the system.

Resources