controladores - AngularJS: Cómo anidar aplicaciones dentro de una aplicación angular
angularjs service (5)
Al igual que en la respuesta anterior de UnicodeSnowman, otra solución potencial que parece estar funcionando para mis necesidades (construí un editor Angular en vivo en un sitio de documentación) es manejar manualmente el proceso de arranque al tener un <div id="demos">
que es independiente desde el principal <div id="myApp">
.
Este artículo fue muy útil para que funcione correctamente.
Proceso general
- Cree su aplicación principal (elegí iniciar manualmente, pero es posible que pueda usar
ng-app
para esta parte) - Crear una nueva estructura / aplicación HTML (en mi caso, la aplicación de demostración):
- Agregúelo al div de demos con un ID personalizado:
someCoolDemoContainer
- Boostrap la aplicación de nueva creación
- Vuelva a colocarlo en la aplicación original (para fines de diseño / posicionamiento)
Ejemplo de código (no probado, solo muestra el proceso básico)
<div id="myApp">
<h1>Demo</h1>
<p>Click the button below to checkout the cool demo!</p>
<button ng-click="showDemo()">Show Demo</button>
<div class=''insertion-point''></div>
</div>
<div id="demos">
</div>
<script type="text/javascript">
/*
* Init/bootstrap our main app
*/
var appContainer = document.getElementById(''myApp'');
angular.module(''myApp'', [''myDependency'']);
angular.bootstrap(appContainer, [''myApp'']);
// Do lots of other things like adding controllers/models/etc.
/*
* Init/bootstrap our demo app when the user clicks a button
*/
function showDemo() {
// Append our demo code
$(''#demos'').append(''<div id="someCoolDemoContainer">Angular app code goes here</div>'');
// Bootstrap the new app
var demoContainer = document.getElementById(''someCoolDemoContainer'');
angular.module(''someCoolDemo'', [''myDependency'']);
angular.module(''someCoolDemo'').controller(''myController'', function() { ... });
angular.bootstrap(demoContainer, [''someCoolDemo'']);
// Re-insert it back into the DOM where you want it
$(''#myApp'').find(''.insertion-point'').append($(''#someCoolDemoContainer''));
}
</script>
He estado trabajando en un proyecto que es más como un marco, y tengo varias aplicaciones / módulos que puedes instalar. Véalo como una tienda de aplicaciones básica o google.play store. Es una especie de aplicación de intranet, y todos los módulos se pueden agregar a su cuenta de usuario.
El marco ya está en desarrollo, pero ahora estoy envolviendo la idea de las aplicaciones / módulos. ( enlace a una prueba de concepto en desarrollo, se puede encontrar aquí )
una aplicación debe ser un tanto independiente, y no poder incluir de forma repentina secuencias de comandos desde el marco. Esto es perfectamente posible estructurándolas en módulos separados de esta manera
angular.module(''myApp'', []);
sin embargo, una aplicación puede tener plantillas, scripts, css y puede ejecutarse en un servidor separado, así que estoy buscando la mejor manera de obtener los scripts y cssfile (s) y cargarlos dinámicamente en la aplicación cuando el usuario inicia la app
desde dentro del marco.
- Actualmente estoy estructurando aplicaciones como si tuvieran una plantilla principal, por ejemplo,
www.framework.com/apps/myapp/views/app.html
, para simplificar los paquetes de scripts en 1 archivo de script por aplicación, por lo que también hay awww.framework.com/apps/myapp/script.js
que se incluirá.
El marco contiene una plantilla que carga las aplicaciones y un appController
. La plantilla contiene esta pieza:
<div data-ng-controller="AppController" data-ng-include="app.appTemplate">
<div>loading...</div>
</div>
esto básicamente se enlaza al $scope.app.appTemplate
que se actualiza cuando se cargan todos los scripts, por lo que primero muestra una plantilla de carga, luego, después de que se incluyan los scripts en la página, se actualiza el app.appTemplate
a la plantilla principal mencionada anteriormente de un solicitud.
Mientras se carga la primera plantilla de índice, esta plantilla se carga actualmente con AppController
desde el marco, por lo que está utilizando el $scope
de $scope
del marco y no su propio script.
Todavía tengo que iniciar de alguna manera el propio módulo angular de la aplicación, y dejarlo por su cuenta sin ejecutar nada en el marco para que funcione.
Todavía estoy pensando en la mejor manera de cargar los archivos javascript dependientes (probablemente usaré requrejs u otro cargador de dependencia) pero actualmente no tengo ni idea de cómo "arrancar" la aplicación sin trabajar desde el AppController
del marco AppController
EDITAR
Creé un pequeño proyecto de demostración para mostrar los problemas a mano, el código completo es visible en git-hub en el momento en que este proyecto hace algunas cosas difíciles de codificar, la idea sería que los hiciera menos rígidos cuando obtengo la prueba de concepto correcto, ahora se trata de cargar las aplicaciones dentro del marco. si eso es posible, puedo pensar en dónde obtener los nombres de URL y aplicaciones de ...
Bueno, si cada sub-aplicación está en su propio módulo, simplemente puede usar angular.bootstrap para cargar ese módulo dinámicamente. cuando se carga la url para una aplicación específica, puede obtener los scripts necesarios, luego, cuando la promesa se resuelva, puede hacer algo como:
// grab a reference to the element where you''ll be loading the sub-app
var subapp = document.getElementById(''subapp-id'');
// assuming the script you get back contains an angular module declaration named
// ''subapp'', manually start the sub-app
angular.bootstrap(angular.element(subapp), [''subapp'']);
espero que esto ayude
Contrariamente a la respuesta actualmente aceptada, en realidad es posible.
Estaba trabajando en un problema similar y la respuesta sugerida no era aceptable en mi caso. Previamente había escrito páginas con múltiples aplicaciones, pero era hace años y las aplicaciones eran independientes entre sí. Hay dos cosas que hacer básicamente:
- Indica a la aplicación principal que ignore un elemento secundario.
- Arranque el elemento hijo.
Existe un atributo ng-non-bindable que simplemente le dice a AngularJS que ignore el elemento. Esto maneja nuestro primer problema.
Sin embargo, cuando intenta arrancar el elemento secundario; AngularJS lanzará un error, diciéndole que ya está bootstrapped (al menos para mí, la versión 1.2.13). El siguiente truco hace el trabajo:
<div ng-non-bindable data-$injector="">
<div id="bootstrap-me">
<script src="/path/to/app.js"></script>
<div ng-include="''/path/to/app.html''"/>
</div>
</div>
Esta solución no es perfecta. Idealmente, el atributo ng-non-bindable puede agregar el atributo data- $ injector requerido al elemento. Voy a hacer una función y, con suerte, una solicitud de extracción a AngularJS.
No tuve la oportunidad de hacer una solicitud de extracción. Al parecer, y como era de esperar, debo decir, algunas partes internas han cambiado, pero ng-non-bindable aún funciona en la versión 1.3.13 con el código de demostración de Ventzy Kunev (gracias de nuevo, consulte el enlace a continuación).
No puede arrancar un módulo dentro de otro módulo de arranque. Bootstrapping compila la vista y le vincula un rootScope, lo atraviesa a través del DOM y configura los enlaces de alcance y ejecuta las funciones de vinculación de directivas hasta el final. Si haces eso dos veces, vas a tener problemas.
Probablemente tendrás que repensar tu arquitectura. Creo que tal vez la palabra "módulo" o "aplicación" en lo que se refiere a Angular sea un nombre inapropiado y lo lleve por el camino equivocado.
Cada "aplicación instalada por el usuario" en su aplicación probablemente debería ser realmente controlada por un controlador en su módulo de aplicación, o registrada en un módulo referenciado por su módulo de aplicación. Por lo tanto, no estaría "iniciando varias aplicaciones", en realidad solo estaría iniciando una, haciendo referencia a los otros módulos y luego utilizando los Controladores de esos módulos para controlar partes de su vista en la pantalla.
Lo que harías es cuando se instaló un nuevo "widget", estás registrado en el archivo del módulo (.js) con el sistema, que contendría un controlador llamado WidgetCtrl, luego, cuando tu página se cargue, harás referencia al widget módulo en su módulo de aplicación. A partir de ahí, debe estar disponible para la asignación dinámica a elementos utilizando ng-controller y / o ng-include.
Espero que tenga sentido.
Sé que esto es bastante viejo ahora, pero estaba buscando una manera de integrar una aplicación AngularJS dentro de una aplicación Angular y usé las respuestas de este post para hacer precisamente eso, así que pensé que iba a publicar el plunker aquí para cualquier persona que esté buscando Una solución similar.
Encontré dos formas de hacerlo, ambas utilizaron el arranque manual de la aplicación angularjs dentro de ngOnInit de un componente Angular:
ngOnInit(): void {
// manually bootstrap the angularjs app
angular.bootstrap(document.getElementById(''ngListApp''), [''list-app'']);
}
O bien, establezca el atributo ngNonBindable en el elemento que será bootstrapped:
<div ngNonBindable #insert>
<!-- can insert the angular js template directly here, inside non-bindable element -->
<div id="ngListApp" ng-controller="ListController as list">
<input ng-model="inputValue" />
<ul>
<li ng-repeat="item in items">{{ item }}</li>
</ul>
</div>
</div>
O inyecte la plantilla angularjs html en el elemento en el controlador de eventos ngOnInit dentro de un componente Angular para que Angular no intente interpretar el código AngularJS (especialmente la interpolación de las propiedades de AngularJS en el DOM con llaves) durante la compilación.
ngOnInit(): void{
// insert angularjs template html here
this.div.nativeElement.innerHTML = this.htmlTemplate;
// then manually bootstrap the angularjs app
angular.bootstrap(document.getElementById(''ngListApp''), [''list-app'']);
}
El Plunker está aquí: