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.

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


@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.


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>

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.


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.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.