¿Cómo crear archivos de controlador AngularJS separados?

315

Tengo todos mis controladores AngularJS en un archivo, controllers.js. Este archivo está estructurado de la siguiente manera:

angular.module('myApp.controllers', [])
  .controller('Ctrl1', ['$scope', '$http', function($scope, $http) {    
  }])
  .controller('Ctrl2', ['$scope', '$http', function($scope, $http) }
  }])

Lo que me gustaría hacer es poner Ctrl1 y Ctrl2 en archivos separados. Luego incluiría ambos archivos en mi index.html, pero ¿cómo debería estructurarse? Intenté hacer algo como esto y arroja un error en la consola del navegador web que dice que no puede encontrar mis controladores. ¿Alguna pista?

Busqué en StackOverflow y encontré esta pregunta similar; sin embargo, esta sintaxis está usando un marco diferente (CoffeeScript) además de Angular, por lo que no he podido seguirla.


AngularJS: ¿Cómo creo controladores en varios archivos?

Beebunny
fuente

Respuestas:

399

Archivo uno:

angular.module('myApp.controllers', []);

Archivo dos:

angular.module('myApp.controllers').controller('Ctrl1', ['$scope', '$http', function($scope, $http){

}]);

Archivo tres:

angular.module('myApp.controllers').controller('Ctrl2', ['$scope', '$http', function($scope, $http){

}]);

Incluir en ese orden. Recomiendo 3 archivos para que la declaración del módulo sea independiente.


En cuanto a la estructura de carpetas, hay muchas, muchas opiniones sobre el tema, pero estas dos son bastante buenas.

https://github.com/angular/angular-seed

http://briantford.com/blog/huuuuuge-angular-apps.html

Fresheyeball
fuente
1
Si el OP indica confusión sobre la sintaxis de CoffeeScript, ¿tal vez sería mejor no usarlo en su respuesta?
Andrew
3
@Andrew Imho ayuda futura y hacer un registro de soluciones es de lo que se trata SO realmente, no q y a extemporáneos.
Fresheyeball
2
@RuslanIsmagilov your appCtrles un global window.appCtrl. Esa no es una buena práctica.
Fresheyeball
1
@Fresheyeball, el problema de este enfoque es que el orden de importación en el index.html es importante, de lo contrario, el error de emisión angular.
Deoxyseia
2
@hendryau, bueno, estaba trabajando con el nombre del módulo presente en el OP. Dicho esto, algunos piensan que es mejor organizativamente, tener múltiples módulos espaciados por nombre, en lugar de un módulo de aplicación central.
Fresheyeball
177

El uso de la API angular.module con una matriz al final le indicará a angular que cree un nuevo módulo:

myApp.js

// It is like saying "create a new module"
angular.module('myApp.controllers', []); // Notice the empty array at the end here

Usarlo sin la matriz es en realidad una función getter. Entonces, para separar sus controladores, puede hacer:

Ctrl1.js

// It is just like saying "get this module and create a controller"
angular.module('myApp.controllers').controller('Ctrlr1', ['$scope', '$http', function($scope, $http) {}]);

Ctrl2.js

angular.module('myApp.controllers').controller('Ctrlr2', ['$scope', '$http', function($scope, $http) {}]);

Durante las importaciones de JavaScript, solo asegúrese de que myApp.js esté detrás de AngularJS pero antes de cualquier controlador / servicios / etc ... de lo contrario, angular no podrá inicializar sus controladores.

Jimmy Au
fuente
¿Dónde debo escribir mis dependencias? var myapp = angular.module ('demo', ['ngRoute', 'ngCookies', 'ui.bootstrap', 'nvd3ChartDirectives', 'ui-rangeSlider', 'textAngular', 'angularTreeview']);
vipin
@vipin al igual que lo que ha escrito, pero asegúrese de que esté por encima de cualquier controlador, servicio, etc. Técnicamente no necesita declarar var myapp = ...; porque angular lo guardará para ti.
Jimmy Au
@JimmyAu ¿Dónde se cargan Ctrl1.js y Ctrl2.js para que la página pueda usarlo? Tengo myApp.js cargado justo después de angular, pero la página no puede encontrar los controladores. ¿Tengo que agregarlos explícitamente como un script en la vista que lo necesita? ¿O todavía tengo que incluir cada archivo de controlador en cada página?
Sinaesthetic
2
Gracias por aclarar por qué solo necesita la primera llamada [].
Jim B.
49

Aunque ambas respuestas son técnicamente correctas, quiero presentar una opción de sintaxis diferente para esta respuesta. Esta información facilita la lectura de lo que sucede con la inyección, la diferencia entre etc.

Archivo uno

// Create the module that deals with controllers
angular.module('myApp.controllers', []);

Archivo dos

// Here we get the module we created in file one
angular.module('myApp.controllers')

// We are adding a function called Ctrl1
// to the module we got in the line above
.controller('Ctrl1', Ctrl1);

// Inject my dependencies
Ctrl1.$inject = ['$scope', '$http'];

// Now create our controller function with all necessary logic
function Ctrl1($scope, $http) {
  // Logic here
}

Archivo tres

// Here we get the module we created in file one
angular.module('myApp.controllers')

// We are adding a function called Ctrl2
// to the module we got in the line above
.controller('Ctrl2', Ctrl2);

// Inject my dependencies
Ctrl2.$inject = ['$scope', '$http'];

// Now create our controller function with all necessary logic
function Ctrl2($scope, $http) {
  // Logic here
}
jason328
fuente
Interesante, me
impide
44
Veo mucha codificación como esta. Cual es la ventaja? de tener $ inject y una función separada.
Alaksandar Jesus Gene
2
Creo que hace que el código sea más fácil de leer. Sé exactamente qué se inyecta. Piense en ello como una "separación de preocupaciones" línea por línea.
jason328
2
Un código como este no solo produce un código más legible, es mucho más fácil de depurar y reduce la cantidad de código de devolución de llamada anidado (consulte github.com/johnpapa/angular-styleguide/blob/master/a1/… )
rfornal
Si pudiera hacer +1 esto 1000 veces, ¡bravo!
Dan Chase
17

¿Qué hay de esta solución? Módulos y controladores en archivos (al final de la página) Funciona con múltiples controladores, directivas, etc.

app.js

var app = angular.module("myApp", ['deps']);

myCtrl.js

app.controller("myCtrl", function($scope) { ..});

html

<script src="app.js"></script>
<script src="myCtrl.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">

Google también tiene recomendaciones de mejores prácticas para la estructura angular de aplicaciones . Realmente me gusta agrupar por contexto. No todos los html en una carpeta, pero por ejemplo todos los archivos para iniciar sesión (html, css, app.js, controller.js, etc.). Entonces, si trabajo en un módulo, todas las directivas son más fáciles de encontrar.

schasoli
fuente
3

Por brevedad, aquí hay una muestra de ES2015 que no se basa en variables globales

// controllers/example-controller.js

export const ExampleControllerName = "ExampleController"
export const ExampleController = ($scope) => {
  // something... 
}

// controllers/another-controller.js

export const AnotherControllerName = "AnotherController"
export const AnotherController = ($scope) => {
  // functionality... 
}

// app.js

import angular from "angular";

import {
  ExampleControllerName,
  ExampleController
} = "./controllers/example-controller";

import {
  AnotherControllerName,
  AnotherController
} = "./controllers/another-controller";

angular.module("myApp", [/* deps */])
  .controller(ExampleControllerName, ExampleController)
  .controller(AnotherControllerName, AnotherController)
Pete TNT
fuente
1
Podría ahorrar bastante tipeo si usara funciones con nombre ... tienen propiedades útiles name... así que simplemente puede usar en ExampleCtrl.namelugar de duplicar ... triplicarlo.
Antti Pihlaja
0

No es tan elegante, pero es una solución de implementación muy simple: el uso de variables globales.

En el "primer" archivo:


window.myApp = angular.module("myApp", [])
....

en el "segundo", "tercero", etc.


myApp.controller('MyController', function($scope) {
    .... 
    }); 
usuario3682640
fuente
uso este código pero aún no puedo cargar mi controlador? arroja un error: Error: [ng: areq] El argumento 'ProductCtrl' no es una función, no se definió.
QViet
77
esta es una práctica realmente mala
Brendan
@Kim Jong Un Verá ese error si no agrega / concatena el controlador al módulo que creó. Por lo que funciona si se utiliza la siguiente sintaxis:angular.module('myApp').controller('ProductCtrl', ['$scope', '$http', function($scope, $http){ //Your ProductCtrl code goes here }]);
Devner
1
@Brendan, simplemente afirmar que algo es una mala práctica es mejor que nada, pero no mucho. Cuéntanos por qué es una mala práctica ayudar a otros.
Mawg dice que reinstalar a Monica el