Using a child controller from another module - angularjs

I've defined a module and made it the main module for my app using the ng-app directive. I added two controllers to the main app using angular.module('myApp').controller(). One of those controllers has page wide scope whereas the other controller is a child controller.
What I'm now trying to do is include a controller that belongs to another module (not the main myApp module), but I can't figure it out. I do not want to globally namespace controllers.
Anyone know how to do this?
Here is what I have so far:
<!doctype html>
<html lang="en" data-ng-app='myApp' data-ng-controller='myApp.mainController'>
<head>
<meta charset="utf-8">
<title>Untitled</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(function() {
var app, module;
//create two modules, one of which will be used for the app base
app = angular.module('myApp', []);
module = angular.module('otherModule', []);
//create main controller for main app
app.controller('myApp.mainController', function($scope) {
$scope.content = 'App main controller content';
});
//create child controller for main app
app.controller('myApp.subController', function($scope) {
$scope.content = 'App sub controller content';
});
//create a controller for the other module
module.controller('othermodule.controller', function($scope) {
$scope.content = 'Other module controller content';
});
});
</script>
</head>
<body>
<!-- output content from main controller from main module: myApp -->
{{content}}
<!-- specify use of main module's child controller and output its content -->
<div data-ng-controller='myApp.subController'>
{{content}}
</div>
<!-- NOT WORKING - ideally should output content from the other module's controller -->
<div data-ng-controller='othermodule.controller'>
{{content}}
</div>
<!-- load angular library -->
<script src="lib/angular/angular.js"></script>
</body>
</html>
This code outputs the following with a JavaScript error essentially saying that the othermodule.controller controller was not found.
App main controller content
App sub controller content
{{content}}
Exact Error:
> Error: Argument 'othermodule.controller' is not a function, got
> undefined
> assertArg#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:1005
> assertArgFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:1016
> #http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:4740
> applyDirectivesToNode/nodeLinkFn/<#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:4322
> forEach#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:140
> nodeLinkFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:4307
> compositeLinkFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:3953
> compositeLinkFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:3956
> nodeLinkFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:4338
> compositeLinkFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:3953
> publicLinkFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:3858
> bootstrap/</<#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:964
> Scope.prototype.$eval#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:7993
> Scope.prototype.$apply#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:8073
> bootstrap/<#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:962
> invoke#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:2843
> bootstrap#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:961
> angularInit#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:936
> #http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:14729
> b.Callbacks/c#http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js:3
> b.Callbacks/p.fireWith#http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js:3
> .ready#http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js:3
> H#http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js:3
>
> http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js
> Line 5687

What you have done currently is "declared" two modules app and module.
When angular bootstraps, you have asked it to bootstrap with app. So now your application bootstraps with app but the app has no reference to your other module ( which is module! ).
So, you will have to either bootstrap your application with app and specify a dependency on module or bootstrap your application with a totally new module and specify a dependency on app and module.
This is how you define a dependency
angular.module('app',['module']);
If you want to create a totally new module and specify both as dependencies
angular.module('myApp',['app','module'])
Note : if you create a totally new module, you will have to bootstrap your angular application with this new module..
<html ng-app="myApp"...

Related

Why run method of this module isn't run? [duplicate]

I'm trying to add two angular apps / modules to one page.
In the fiddles below you can see that always only the first module, referenced in the html code, will work correctly, whereas the second is not recognized by angular.
In this fiddle we can only execute the doSearch2 method, whereas in this fiddle only the doSearch method works correctly.
I'm looking for the way how to correctly place two angular modules into one page.
Only one AngularJS application can be auto-bootstrapped per HTML document. The first ngApp found in the document will be used to define the root element to auto-bootstrap as an application. To run multiple applications in an HTML document you must manually bootstrap them using angular.bootstrap instead. AngularJS applications cannot be nested within each other.
-- http://docs.angularjs.org/api/ng.directive:ngApp
See also
https://groups.google.com/d/msg/angular/lhbrIG5aBX4/4hYnzq2eGZwJ
http://docs.angularjs.org/api/angular.bootstrap
I created an alternative directive that doesn't have ngApp's limitations. It's called ngModule. This is what you code would look like when you use it:
<!DOCTYPE html>
<html>
<head>
<script src="angular.js"></script>
<script src="angular.ng-modules.js"></script>
<script>
var moduleA = angular.module("MyModuleA", []);
moduleA.controller("MyControllerA", function($scope) {
$scope.name = "Bob A";
});
var moduleB = angular.module("MyModuleB", []);
moduleB.controller("MyControllerB", function($scope) {
$scope.name = "Steve B";
});
</script>
</head>
<body>
<div ng-modules="MyModuleA, MyModuleB">
<h1>Module A, B</h1>
<div ng-controller="MyControllerA">
{{name}}
</div>
<div ng-controller="MyControllerB">
{{name}}
</div>
</div>
<div ng-module="MyModuleB">
<h1>Just Module B</h1>
<div ng-controller="MyControllerB">
{{name}}
</div>
</div>
</body>
</html>
You can get the source code at:
http://www.simplygoodcode.com/2014/04/angularjs-getting-around-ngapp-limitations-with-ngmodule/
It's essentially the same code used internally by AngularJS without the limitations.
Why do you want to use multiple [ng-app] ? Since Angular is resumed by using modules, you can use an app that use multiple dependencies.
Javascript:
// setter syntax -> initializing other module for demonstration
angular.module('otherModule', []);
angular.module('app', ['otherModule'])
.controller('AppController', function () {
// ...do something
});
// getter syntax
angular.module('otherModule')
.controller('OtherController', function () {
// ...do something
});
HTML:
<div ng-app="app">
<div ng-controller="AppController">...</div>
<div ng-controller="OtherController">...</div>
</div>
EDIT
Keep in mind that if you want to use controller inside controller you have to use the controllerAs syntax, like so:
<div ng-app="app">
<div ng-controller="AppController as app">
<div ng-controller="OtherController as other">...</div>
</div>
</div>
You can bootstrap multiple angular applications, but:
1) You need to manually bootstrap them
2) You should not use "document" as the root, but the node where the angular interface is contained to:
var todoRootNode = jQuery('[ng-controller=TodoController]');
angular.bootstrap(todoRootNode, ['TodoApp']);
This would be safe.
Manual bootstrapping both the modules will work. Look at this
<!-- IN HTML -->
<div id="dvFirst">
<div ng-controller="FirstController">
<p>1: {{ desc }}</p>
</div>
</div>
<div id="dvSecond">
<div ng-controller="SecondController ">
<p>2: {{ desc }}</p>
</div>
</div>
// IN SCRIPT
var dvFirst = document.getElementById('dvFirst');
var dvSecond = document.getElementById('dvSecond');
angular.element(document).ready(function() {
angular.bootstrap(dvFirst, ['firstApp']);
angular.bootstrap(dvSecond, ['secondApp']);
});
Here is the link to the Plunker
http://plnkr.co/edit/1SdZ4QpPfuHtdBjTKJIu?p=preview
NOTE: In html, there is no ng-app. id has been used instead.
I made a POC for an Angular application using multiple modules and router-outlets to nest sub apps in a single page app.
You can get the source code at: https://github.com/AhmedBahet/ng-sub-apps
Hope this will help

Can AngularJS apps / modules contain controllers from other apps / modules?

Can I create a module for authentication and then bind to its controllers from a view in another app / module? For example, creating a common LoginController and then have login pages in my other apps that would use this controller? If so, how? I cannot find any examples but the docs make me think this is possible.
Yeah so long as you have a script/module loaded up and set as the dependency of your app used for the ng-app or for manually bootstrapping the app then you can use any of the controllers/providers defined in those modules.
angular.module('A',['B']);
angular.module('B', []).controller('MyController',function($scope){ $scope.doSomething = function(){alert('did something')}});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="A">
<div ng-controller="MyController">
<button ng-click="doSomething()">Do Something</button>
</div>
</div>
You could have multiple modules by that you can separate out your code.
Basically you can create a separate module for your LoginController, like
angular.module('authentication',[])
.controller('LoginController', function($scope){
//code here
});
then you main app module you should add this module
angular.module('app',['authentication']
Then you can use this app module as ng-app or you could bootsrap the same module.

Angular binding for dynamically added html div

Sorry, this seems a duplicated questions, but I tried all answered questions close to my question, with no success.
I am trying to introduce angular.js into a legacy system.
the system is using the .load jquery function to dynamically load div content with a page from an ASP.NET MVC page.
my brief html will look like this
<body ng-app="myApp">
<div ng-controller="myCtrl">
any content...
<div id="dyncontent"> </div>
</div>
and my javascript legacy code looks like
$('#dyncontent').load('/showviewcontent');
I added in the dynamic content, some angular directive and binding instruction
my angular code is like this
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', function ($scope) {
.....
});
How to make the binding / angular directive works on the newly added content?
You need to manually start the angular module using angular.bootstrap
$('#dyncontent').load('/showviewcontent', function() {
angular.bootstrap(document.getElementById('dyncontent'), ['myApp']);
});

Angular.js: How to reload scope?

I have some markup and loaded controllers.
Then I load some modal window contents by ajax, which is using one of controllers I have defined before. But looks like this controller isn't being used, because he is not required until modal loaded.
Question: How to make controller work when modal loaded? I tryied $scope.$digest(), got error "digest in progress".
index.html
<html data-ng-app="foo">
<head>
<script src="/js/app.js"></script>
</head>
<body>
<div id="modal"></div>
</body>
</html>
js/app.js
!(function(){
function FormCtrl($scope) {
console.log($scope); // never fired
$scope.Submit = function() {
console.log('submit'); // never fired too :C
}
}
angular.module('foo', []).controller('FormCtrl', FormCtrl);
})();
html content loaded by ajax and inserted to #modal
<div data-ng-controller="FormCtrl">
<form name="signup" data-ng-submit="Submit()">
<!-- form data -->
</form>
</div>
SOLUTION:
$.modal().open({
onOpen: function($e) {
$http.get('/views/' + url).success(function(data) {
$compile(data)($scope, function(clonedElem) {
$e.html(clonedElem);
});
// $e.html(data); was used instead of statement above
});
}
});
If you want to inject new DOM elements into existing Anuglar app. You options are to use
ng-include: This has a src property that takes the url from which partial content has to be loaded. AngularJS would internally compile it. One important thing here is that angular will download the template as soon it encounter ng-include in html.
Download and compile DOM manually using the $compile service which is a more involved process.
If your AJAX content contains a controller defined in ng-controller, AngularJS would create it for you.
But in any case, keep in mind the controller script should have been already wired at the initialization\setup phase.

Multiple angularjs applications for one page [duplicate]

I'm trying to add two angular apps / modules to one page.
In the fiddles below you can see that always only the first module, referenced in the html code, will work correctly, whereas the second is not recognized by angular.
In this fiddle we can only execute the doSearch2 method, whereas in this fiddle only the doSearch method works correctly.
I'm looking for the way how to correctly place two angular modules into one page.
Only one AngularJS application can be auto-bootstrapped per HTML document. The first ngApp found in the document will be used to define the root element to auto-bootstrap as an application. To run multiple applications in an HTML document you must manually bootstrap them using angular.bootstrap instead. AngularJS applications cannot be nested within each other.
-- http://docs.angularjs.org/api/ng.directive:ngApp
See also
https://groups.google.com/d/msg/angular/lhbrIG5aBX4/4hYnzq2eGZwJ
http://docs.angularjs.org/api/angular.bootstrap
I created an alternative directive that doesn't have ngApp's limitations. It's called ngModule. This is what you code would look like when you use it:
<!DOCTYPE html>
<html>
<head>
<script src="angular.js"></script>
<script src="angular.ng-modules.js"></script>
<script>
var moduleA = angular.module("MyModuleA", []);
moduleA.controller("MyControllerA", function($scope) {
$scope.name = "Bob A";
});
var moduleB = angular.module("MyModuleB", []);
moduleB.controller("MyControllerB", function($scope) {
$scope.name = "Steve B";
});
</script>
</head>
<body>
<div ng-modules="MyModuleA, MyModuleB">
<h1>Module A, B</h1>
<div ng-controller="MyControllerA">
{{name}}
</div>
<div ng-controller="MyControllerB">
{{name}}
</div>
</div>
<div ng-module="MyModuleB">
<h1>Just Module B</h1>
<div ng-controller="MyControllerB">
{{name}}
</div>
</div>
</body>
</html>
You can get the source code at:
http://www.simplygoodcode.com/2014/04/angularjs-getting-around-ngapp-limitations-with-ngmodule/
It's essentially the same code used internally by AngularJS without the limitations.
Why do you want to use multiple [ng-app] ? Since Angular is resumed by using modules, you can use an app that use multiple dependencies.
Javascript:
// setter syntax -> initializing other module for demonstration
angular.module('otherModule', []);
angular.module('app', ['otherModule'])
.controller('AppController', function () {
// ...do something
});
// getter syntax
angular.module('otherModule')
.controller('OtherController', function () {
// ...do something
});
HTML:
<div ng-app="app">
<div ng-controller="AppController">...</div>
<div ng-controller="OtherController">...</div>
</div>
EDIT
Keep in mind that if you want to use controller inside controller you have to use the controllerAs syntax, like so:
<div ng-app="app">
<div ng-controller="AppController as app">
<div ng-controller="OtherController as other">...</div>
</div>
</div>
You can bootstrap multiple angular applications, but:
1) You need to manually bootstrap them
2) You should not use "document" as the root, but the node where the angular interface is contained to:
var todoRootNode = jQuery('[ng-controller=TodoController]');
angular.bootstrap(todoRootNode, ['TodoApp']);
This would be safe.
Manual bootstrapping both the modules will work. Look at this
<!-- IN HTML -->
<div id="dvFirst">
<div ng-controller="FirstController">
<p>1: {{ desc }}</p>
</div>
</div>
<div id="dvSecond">
<div ng-controller="SecondController ">
<p>2: {{ desc }}</p>
</div>
</div>
// IN SCRIPT
var dvFirst = document.getElementById('dvFirst');
var dvSecond = document.getElementById('dvSecond');
angular.element(document).ready(function() {
angular.bootstrap(dvFirst, ['firstApp']);
angular.bootstrap(dvSecond, ['secondApp']);
});
Here is the link to the Plunker
http://plnkr.co/edit/1SdZ4QpPfuHtdBjTKJIu?p=preview
NOTE: In html, there is no ng-app. id has been used instead.
I made a POC for an Angular application using multiple modules and router-outlets to nest sub apps in a single page app.
You can get the source code at: https://github.com/AhmedBahet/ng-sub-apps
Hope this will help

Resources