Как говорится в древней пословице – сколько людей столько и стилей написания кода. В сегодняшней статье я хотел бы расскрыть все особенности правильной настройки структуры AngularJS.
Как в любом приложении у нас должна быть точка входа, начальная точка откуда будет стартовать наше приложение. За частую я использую просто app. В этом файле, который не плохо было бы назвать main.js мы напишем такой код:
(function(ng) {
var app = ng.app('app', []);
// This should be your configuration like a routeProvider or etc.
return app;
})(angular);
Также этот модуль будет в будущем включать остальные модули за счет dependency injection.
Что же начало положено и не плохо было бы определиться со структурой приложения. Определим определенные сущности нашего приложения. Создадим папки: animations, controllers, factories, directives. По сути, сейчас мы сформируем тот подход, что используется в Java package.
Итак, каждая из директорий что мы создали должна также содержать свои точки входа, опять же таки именуемые main.js. Для примера рассмотрим директорию с контроллерами. В main.js прописываем такой код:
(function(ng) {
var app = ng.app('app.controllers', []);
return app;
})(angular);
Как можно заметить, этот модуль будет отвечать за внедрение контроллеров, которые мы объявим ниже. Также теперь мы можем включить этот модуль в зависимости основного модуля, который примет вид:
(function(ng) {
var app = ng.app('app', ['app.controllers']);
// This should be your configuration like a routeProvider or etc.
return app;
})(angular);
Теперь опишем пару контроллеров для нашего приложения, чтобы показать как мы можем использовать. Есть определенные соглашения с названием контроллеров, а именно в стиле camel-case как класс. Чтоже создадим файл в директории controllers MainCtrl.js, который будем содержать нашу логику контроллера. Его содержимое будет примерно такое:
(function(ng) {
var app = ng.app('app.controllers.MainCtrl', []);
var MainCtrl = function($scope) {
var localScope = {
message: 'Message',
list: [1,2,3,4,5,6]
};
ng.extend($scope, localScope);
};
app.controller('MainCtrl', ['$scope', MainCtrl]);
return app;
})(angular);
Давайте разберем, почему такой подход имеет право на жизнь. Как и раньше у нас объявлен модуль, который будет встроен в зависимости основного модуля контроллеров. Сам код контроллера вынесен в отдельную функцию. После этого он включен как контроллер и использована полная запись объявления контроллера для того чтобы он не был сломан после минимизации и обфускации. Как можно заметить, в нашем контроллере создана локальная переменная как localScope. Для чего это сделано? При небольшом колличестве переменных в $scope это особо не заметно, но когда их становится много, кода становится немного не читабельным и поэтому я просто взял технику расширения основного $scope через метод angularjs extend. Как по мне, такой способ красив, лаконичен и довольно читаем. Также добавим наш контроллер в зависимоть нашего основного модуля для контроллеров. Его код будет таким:
(function(ng) {
var app = ng.app('app.controllers', ['app.controllers.MainCtrl']);
return app;
})(angular);
По такому принципу мы будем строить и другие зависимоти для директив, фабрик и так далее. Как по мне, такой подход дает полное понимание вашего приложения, его структура сразу становится видна и очень просто модернизировать, добавляя новые контроллеры, сервисы, директивы и прочее.
В заключение я хотел бы поговорить немного о контроллерах, вернее о новом синтаксисе “as”
Если мы не хотим чтобы наши переменные или же какие-то функции были observable. То мы можем полноценно использовать такой подход:
(function(ng) {
var app = ng.app('app.controllers.MainCtrl', []);
var MainCtrl = function($scope, $log) {
var localScope = {
message: 'Message',
list: [1,2,3,4,5,6]
};
this.nonObservableVar = {
one: 1,
two: 2
};
this.logger = function(obj) {
$log.info(obj);
};
ng.extend($scope, localScope);
};
app.controller('MainCtrl', ['$scope', '$log', MainCtrl]);
return app;
})(angular);
И в нашем view использовать такой код:
<div ng-controller="MainCtrl as main">
<div ng-click="main.logger('Test for a one value')">{{ main.nonObservableVar.one }}</div>
<div ng-click="main.logger('Test for a two value')">{{ main.nonObservableVar.two }}</div>
</div>
Что это нам дает? Ну одно из преимуществ, то что тут нет angular watcher’ов. Это ускоряет наше приложение, также дает возможность в вложенных контроллерах использовать контекст родительских контроллеров, что дает возможность более гибко строить наше приложение. Этот способ очень прост в использовании. Как и раньше мы также можем смешивать переменные контроллера с переменными $scope для возможности использования $watch, $apply, etc.
Если интересно, буду дальше писать про angular и как на нем строить красивые и структурированные приложения. В плане написать статью про использования angularjs с requirejs и прекрасной фичей requirejs – пакеты.
Оставляйте свои отзывы в комменариях.
PS: Я написал этот пост для того, чтобы ваше приложение можно было легко поддерживать и в дальнейшем, чтобы тот, кто будет дорабатывать ваше приложение понимал, что и как у вас там =)
Автор: xGromMx