119

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.

6 Answers 6

124

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

Sign up to request clarification or add additional context in comments.

9 Comments

@MarkRajcok So is it good practice to only have one module per HTML document? The "Wire up a Backend" example on the main AngularJS page sets ng-app="project" and says that "this lets you have modules that run in different parts of the page" but the ngApp doc states that "only one directive can be used per HTML document".
@mattblang, modules are associated with Angular applications, and not really HTML documents. Normally you only need one app per page/document, but if you want to run multiple Angular applications (each of which can use one or more modules) on the same page/document, then you'll need to manually bootstrap each of them -- don't use ng-app (because it won't work). ng-app can only be used once per HTML document. It is really just a short-cut if you only have one app on the page, which is the normal case.
Is there an example of this? I see the terse boostrap api documentation but I am not able to get it to work. I have googled this for a while and there doesn't seem to be a single working example. Additionally, how in the world would this work with routes? Obviously there is a collision issue.
Also, I really like the way using ng-app shows another developer exactly which part of the page is being controlled by what module. Is there no way to use markup on the page to accomplish this? Or at least, some hint in the markup?
The first two paragraphs for the ng-app directive says it all - docs.angularjs.org/api/ng.directive:ngApp
|
38

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.

5 Comments

luisperezphd: I read your blog post. Is there any way to nest apps (e.g. a widget builder with an AJAX loaded widget) or detect if a page already has an app and inject another app as a dependency of the first? I just posted my question here with more details of exactly what I'm trying to accomplish. Thanks!
@ACIDSTEALTH The fact that AngularJS is reporting that the element already bootstrapped means that there must be some way to tell - though that code might be internal to AngularJS. To find out you could reference the unminified version of AngularJS and breakpoint on that error to see the if condition. From what I can make out from your StackOverflow question link, it sounds like you want to dynamically "inject" a module at runtime. If so you might want to take a look at this article: weblogs.asp.net/dwahlin/…
Hey @LuisPerez , I checked your website. I tired it on my machine . angularJS is not detecting "ng-modules"/"ng-module" . Do I need any references included in my file ?
Yes @sujaykodamala, ngModule is not built into AngularJS it's a directive I created. You can download it from GitHub. You can find it here: github.com/luisperezphd/ngModule
Hello @Luis Perez! I was checking your blog post and they are really awesome. If you have time, could you please check my post here to resolve an issue - stackoverflow.com/questions/46952478/…. Thanks.
19

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>

4 Comments

Uncaught Error: [$injector:modulerr] errors.angularjs.org/1.3.14/$injector/……criptMinification%2Fbower_components%2Fangular%2Fangular.min.js%3A17%3A381)
Have you tried to invert order of the 2 modules ?('otherModule' before 'app') Because, I use this solution a lot and it works perfectly...
Ok ! I've seen an error in the Javascript exemple that I provide. I think it is fixed now ! For the record, I'll used the setter syntax in 2 places for the same module... which is obviously not permitted! :-)
the way we 'pose to do it
10

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.

Comments

3

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.

Comments

0

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.