Como criar arquivos separados do controlador AngularJS?

315

Eu tenho todos os meus controladores AngularJS em um arquivo, controllers.js. Este arquivo está estruturado da seguinte maneira:

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

O que eu gostaria de fazer é colocar Ctrl1 e Ctrl2 em arquivos separados. Eu incluiria os dois arquivos no meu index.html, mas como isso deve ser estruturado? Tentei fazer algo assim e ele gera um erro no console do navegador dizendo que não consegue encontrar meus controladores. Alguma dica?

Pesquisei no StackOverflow e encontrei essa pergunta semelhante - no entanto, essa sintaxe está usando uma estrutura diferente (CoffeeScript) no topo do Angular, e por isso não consegui segui-lo.


AngularJS: Como criar controladores em vários arquivos

Beebunny
fonte

Respostas:

399

Arquivo um:

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

Arquivo dois:

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

}]);

Arquivo três:

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

}]);

Incluir nessa ordem. Eu recomendo 3 arquivos para que a declaração do módulo seja por si só.


Quanto à estrutura de pastas, existem muitas opiniões sobre o assunto, mas essas duas são muito boas

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

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

Fresheyeball
fonte
1
Se o OP indicasse confusão sobre a sintaxe do CoffeeScript, talvez fosse melhor não usá-lo em sua resposta?
Andrew
3
@ Andrew imho ajuda futura e fazer um registro de soluções é o que realmente interessa a SO, não q e a extemporâneo.
Fresheyeball 10/03/14
2
@RuslanIsmagilov your appCtrlé um global window.appCtrl. Essa não é uma boa prática.
Fresheyeball
1
@Fresheyeball, o problema dessa abordagem é que a ordem de importação no index.html é importante, caso contrário, o erro de emissão angular.
Deoxyseia 10/10
2
@ Hendryau, bem, eu estava trabalhando com o nome do módulo presente no OP. Dito isto, alguns acham que é melhor organizacional ter vários módulos espaçados por nome, em vez de um módulo de aplicativo central.
Fresheyeball
177

O uso da API angular.module com uma matriz no final indicará ao angular para criar um novo módulo:

myApp.js

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

Usá-lo sem a matriz é na verdade uma função getter. Portanto, para separar seus controladores, você pode:

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 as importações de javascript, verifique se o myApp.js está atrás do AngularJS, mas antes de qualquer controlador / serviço / etc ... caso contrário, o angular não poderá inicializar seus controladores.

Jimmy Au
fonte
onde devo escrever minhas dependências. var myapp = angular.module ('demo', ['ngRoute', 'ngCookies', 'ui.bootstrap', 'nvd3ChartDirectives', 'ui-rangeSlider', 'textAngular', 'angularTreeview']);
vipin
@ vipin como o que você digitou, mas verifique se está acima de quaisquer controladores, serviços, etc. Tecnicamente, você não precisa declarar var myapp = ...; porque angular irá armazená-lo para você.
Jimmy Au
@JimmyAu Onde o Ctrl1.js e o Ctrl2.js são carregados para que a página possa usá-lo? Tenho o myApp.js carregado logo após o angular, mas a página não consegue encontrar os controladores. Tenho que adicioná-los explicitamente como um script na exibição que precisa? Ou ainda preciso incluir todos os arquivos do controlador em todas as páginas?
Sinaesthetic
2
Obrigado por esclarecer por que apenas a primeira chamada precisa [].
Jim B.
49

Embora ambas as respostas sejam tecnicamente corretas, quero apresentar uma opção de sintaxe diferente para esta resposta. Esse imho facilita a leitura do que está acontecendo com a injeção, a diferenciação entre etc.

Arquivo Um

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

Arquivo dois

// 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
}

Arquivo três

// 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
fonte
Interessante, ele faz me impedir de ir a vários arquivos para registrar um controlador
mrwaim
4
Eu vejo muitas codificações como essa. Qual a vantagem? de ter $ injetar e uma função separada.
Alaksandar Jesus Gene
2
Eu acredito que torna o código mais fácil de ler. Eu sei o que exatamente está sendo injetado. Pense nisso como uma "separação de preocupações", linha por linha.
precisa saber é o seguinte
2
Um código como esse não apenas produz código mais legível, é muito mais fácil de depurar e reduz a quantidade de código de retorno de chamada aninhado (consulte github.com/johnpapa/angular-styleguide/blob/master/a1/… )
rfornal
Se eu pudesse marcar +1 isso 1000 vezes eu faria - bravo!
Dan Chase
17

E essa solução? Módulos e controladores em arquivos (no final da página) Funciona com vários controladores, diretivas e assim por diante:

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

O Google também possui recomendações de práticas recomendadas para a estrutura angular de aplicativos que eu realmente gosto de agrupar por contexto. Nem todo o html em uma pasta, mas, por exemplo, todos os arquivos para login (html, css, app.js, controller.js e assim por diante). Portanto, se eu trabalhar em um módulo, todas as diretivas serão mais fáceis de encontrar.

Schasoli
fonte
3

Para resumir, aqui está uma amostra do ES2015 que não depende de variáveis ​​globais

// 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
fonte
1
Você poderia economizar um pouco de digitação se usasse funções nomeadas .. elas possuem propriedades úteis name.. então você pode simplesmente usar em ExampleCtrl.namevez de duplicar .. triplicar.
Antti Pihlaja
0

Não é tão elegante, mas muito simples na solução de implementação - usando variável global.

No "primeiro" arquivo:


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

no "segundo", "terceiro", etc:


myApp.controller('MyController', function($scope) {
    .... 
    }); 
user3682640
fonte
Eu uso esse código, mas ainda não consigo carregar meu controlador? lança erro: Erro: [ng: areq] O argumento 'ProductCtrl' não é uma função, ficou indefinido.
QViet
7
isso é realmente má prática
Brendan
@ Kim Jong Un Você verá esse erro se não adicionar / concatenar o controlador ao módulo que você criou. Portanto, funcionará se você usar a seguinte sintaxe:angular.module('myApp').controller('ProductCtrl', ['$scope', '$http', function($scope, $http){ //Your ProductCtrl code goes here }]);
Devner
1
@Brendan, simplesmente afirmando que algo é uma prática ruim é melhor que nada - mas não muito. Diga-nos por que a prática ruim ajudará os outros.
Mawg diz que restabelece Monica