Como definir dois aplicativos / módulos angulares em uma página?

118

Estou tentando adicionar dois aplicativos / módulos angulares a uma página. Nos fiddles abaixo você pode ver que sempre apenas o primeiro módulo, referenciado no código html, funcionará corretamente, enquanto o segundo não é reconhecido pelo angular.

Neste violino podemos apenas executar o doSearch2método, enquanto neste violino apenas o doSearchmétodo funciona corretamente.

Estou procurando uma maneira de colocar corretamente dois módulos angulares em uma página.

Thomas Kremmel
fonte

Respostas:

123

Apenas um aplicativo AngularJS pode ser autoinicializado por documento HTML. O primeiro ngApp encontrado no documento será usado para definir o elemento raiz para autoinicialização como um aplicativo. Para executar vários aplicativos em um documento HTML, você deve inicializá-los manualmente usando angular.bootstrap. Os aplicativos AngularJS não podem ser aninhados uns nos outros. - http://docs.angularjs.org/api/ng.directive:ngApp

Veja também

Mark Rajcok
fonte
@MarkRajcok Portanto, é uma boa prática ter apenas um módulo por documento HTML? O exemplo "Conectar um Backend" nos conjuntos de páginas principais do AngularJS ng-app="project"e diz que "isso permite que você tenha módulos que rodam em diferentes partes da página", mas o documento ngApp afirma que "apenas uma diretiva pode ser usada por documento HTML".
theblang
9
@mattblang, os módulos estão associados a aplicativos Angular e não a documentos HTML. Normalmente, você só precisa de um aplicativo por página / documento, mas se quiser executar vários aplicativos angulares (cada um dos quais pode usar um ou mais módulos) na mesma página / documento, você precisará inicializar manualmente cada um deles - - não use ng-app(porque não vai funcionar). ng-appsó pode ser usado uma vez por documento HTML. Na verdade, é apenas um atalho se você tiver apenas um aplicativo na página, o que é normal.
Mark Rajcok
1
Existe um exemplo disso? Vejo a documentação concisa da API de boostrap, mas não consigo fazê-la funcionar. Pesquisei no Google por um tempo e não parece haver um único exemplo que funcione. Além disso, como no mundo isso funcionaria com as rotas? Obviamente, há um problema de colisão.
Robert Christian
Além disso, gosto muito da maneira como o ng-app mostra a outro desenvolvedor exatamente qual parte da página está sendo controlada por qual módulo. Não há como usar marcação na página para fazer isso? Ou, pelo menos, alguma dica na marcação?
chrismarx
1
Os primeiros dois parágrafos da diretiva ng-app dizem tudo - docs.angularjs.org/api/ng.directive:ngApp
simo
38

Eu criei uma diretiva alternativa que não tem ngApplimitações. É chamado ngModule. Esta é a aparência de seu código ao usá-lo:

<!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>

Você pode obter o código-fonte em:

http://www.simplygoodcode.com/2014/04/angularjs-getting-around-ngapp-limitations-with-ngmodule/

É essencialmente o mesmo código usado internamente pelo AngularJS sem limitações.

Luis Perez
fonte
luisperezphd: Eu li sua postagem no blog. Existe alguma maneira de aninhar aplicativos (por exemplo, um construtor de widget com um widget carregado AJAX) ou detectar se uma página já tem um aplicativo e injetar outro aplicativo como uma dependência do primeiro? Acabei de postar minha pergunta aqui com mais detalhes do que exatamente estou tentando realizar. Obrigado!
Daniel Bonnell
@ACIDSTEALTH O fato de AngularJS relatar que o elemento já foi inicializado significa que deve haver alguma forma de saber - embora esse código possa ser interno ao AngularJS. Para descobrir, você pode consultar a versão não minimizada do AngularJS e o ponto de interrupção desse erro para ver a condição if. Pelo que posso entender no link da sua pergunta StackOverflow, parece que você deseja "injetar" dinamicamente um módulo no tempo de execução. Se sim, você pode querer dar uma olhada neste artigo: weblogs.asp.net/dwahlin/…
Luis Perez
Olá @LuisPerez, verifiquei o seu site. Eu cansei na minha máquina. angularJS não está detectando "ng-modules" / "ng-module". Eu preciso de alguma referência incluída no meu arquivo?
sujay kodamala
Sim @sujaykodamala, ngModule não está embutido no AngularJS, é uma diretiva que criei. Você pode baixá-lo do GitHub. Você pode encontrá-lo aqui: github.com/luisperezphd/ngModule
Luis Perez
Olá @Luis Perez! Eu estava verificando sua postagem no blog e eles são realmente incríveis. Se você tiver tempo, pode verificar minha postagem aqui para resolver um problema - stackoverflow.com/questions/46952478/… . Obrigado.
user8512043
19

Por que você deseja usar vários [ng-app]? Como o Angular é retomado usando módulos, você pode usar um aplicativo que usa várias dependências.

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>

EDITAR

Lembre-se de que se quiser usar o controlador dentro do controlador, você deve usar a sintaxe controllerAs, assim:

<div ng-app="app">
    <div ng-controller="AppController as app">
        <div ng-controller="OtherController as other">...</div>
    </div>
</div>
Monge Macaco
fonte
Erro não detectado: [$ injector: modulerr] errors.angularjs.org/1.3.14/$injector/…… criptMinification% 2Fbower_components% 2Fangular% 2Fangular.min.js% 3A17% 3A381)
Anandaraja_Srinivasan
Você já tentou inverter a ordem dos 2 módulos? ('OtherModule' antes de 'app') Porque, eu uso muito essa solução e ela funciona perfeitamente ...
Monkey Monk
1
Está bem ! Eu vi um erro no exemplo de Javascript que forneço. Acho que já está consertado! Só para constar, vou usar a sintaxe do setter em 2 lugares para o mesmo módulo ... o que obviamente não é permitido! :-)
Monge Macaco
a maneira como fazemos pose
Harry Bosh
9

Você pode inicializar vários aplicativos angulares, mas:

1) Você precisa inicializá-los manualmente

2) Você não deve usar "documento" como raiz, mas o nó onde a interface angular está contida para:

var todoRootNode = jQuery('[ng-controller=TodoController]');
angular.bootstrap(todoRootNode, ['TodoApp']);

Isso seria seguro.

Wouter
fonte
3

A inicialização manual de ambos os módulos funcionará. Veja isso

  <!-- 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']);
});

Aqui está o link para o Plunker http://plnkr.co/edit/1SdZ4QpPfuHtdBjTKJIu?p=preview

NOTA: Em html, não existe ng-app. idfoi usado em seu lugar.

Hari Das
fonte
0

Fiz um POC para um aplicativo Angular usando vários módulos e saídas de roteador para aninhar subaplicativos em um aplicativo de página única. Você pode obter o código-fonte em: https://github.com/AhmedBahet/ng-sub-apps

Espero que isso ajude

abahet
fonte