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.

Thomas Kremmel
  • 14,575
  • 26
  • 108
  • 177

6 Answers6

123

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

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • @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". – theblang May 28 '13 at 15:42
  • 9
    @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. – Mark Rajcok May 29 '13 at 02:45
  • 1
    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. – Robert Christian May 31 '13 at 20:37
  • 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? – chrismarx Aug 27 '13 at 13:58
  • You could use a data attribute, something like `data-ng-app='whatever'`, as a sort of fancy comment, but it seems to me that anyone familiar enough with angular will be able to figure out the manual bootstrapping too. – tandrewnichols Sep 17 '13 at 15:33
  • 1
    The first two paragraphs for the ng-app directive says it all - http://docs.angularjs.org/api/ng.directive:ngApp – simo Jan 14 '14 at 14:29
  • I'm doing this (angular.bootstrap()) using requirejs for modules contained in divs on my page when the required scripts are loaded. If I bootstrap a newly added div, is everything cleaned up/disposed of if the DOM element is removed? if not, is there a way of doing this? – sambomartin Jul 30 '14 at 09:14
  • One of the best solution here Very Much Appreciated. – 3 rules May 14 '16 at 10:06
  • I was trying to do this on a wordpress meta box, so I could have multiple on a page and was losing my mind. You basically have to delete all the ng-apps and manually bootstrap them. I found that putting the bootstrap method in my js file didn't work. I had to add it to the page with the html for the widget; it seemed like the containers I was bootstrapping to didn't exist at the time my modules were being loaded, for whatever reason. – John Proestakes Jun 11 '16 at 15:34
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.

Luis Perez
  • 27,650
  • 10
  • 79
  • 80
  • 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](https://stackoverflow.com/questions/34730849/angular-bootstrap-error-error-ngbtstrpd-app-already-bootstrapped-with-this) with more details of exactly what I'm trying to accomplish. Thanks! – Daniel Bonnell Jan 11 '16 at 21:00
  • @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: http://weblogs.asp.net/dwahlin/dynamically-loading-controllers-and-views-with-angularjs-and-requirejs – Luis Perez Jan 11 '16 at 21:44
  • 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 ? – sujay kodamala May 11 '16 at 15:13
  • 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: https://github.com/luisperezphd/ngModule – Luis Perez May 11 '16 at 18:14
  • 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 - https://stackoverflow.com/questions/46952478/pass-service-as-a-controller-parameter. Thanks. – user8512043 Oct 26 '17 at 19:12
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>
Monkey Monk
  • 984
  • 9
  • 19
  • Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.3.14/$injector/modulerr?p0=mainModule&p1=Erro…criptMinification%2Fbower_components%2Fangular%2Fangular.min.js%3A17%3A381) – Anandaraja_Srinivasan Mar 02 '15 at 13:08
  • Have you tried to invert order of the 2 modules ?('otherModule' before 'app') Because, I use this solution a lot and it works perfectly... – Monkey Monk Mar 03 '15 at 17:05
  • 1
    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! :-) – Monkey Monk Mar 03 '15 at 17:10
  • the way we 'pose to do it – Harry Bosh Feb 13 '17 at 02:28
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.

Wouter
  • 1,678
  • 3
  • 20
  • 32
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.

Hari Das
  • 10,145
  • 7
  • 62
  • 59
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

abahet
  • 10,355
  • 4
  • 32
  • 23