Улучшить эту документациюКонтроллеры
В Angular контроллер определяется функцией JavaScript-конструктором, которая используется для расширения объекта Angular Scope.
Когда контроллер прикреплён к DOM с помощью директивы ng-controller, Angular создаст новый объект контроллера, используя указанную функцию-конструктор контроллера. Будет создан новый вложенный scope, доступный в качестве параметра для инъекции в конструктор функции контроллера как $scope.
Если контроллер прикреплён с использованием controller as синтаксиса, то экземпляр контроллера будет назначен в свойство нового scope.
Используйте контроллеры для:
- Настройки начального состояния объекта
$scope. - Добавления поведения к объекту
$scope.
Не используйте контроллеры для:
- Изменения DOM — контроллеры должны содержать только бизнес-логику. Включение какой-либо презентационной логики в контроллеры значительно ухудшает его тестируемость. Angular предоставляет привязку данных для большинства случаев и директивы для инкапсуляции ручного изменения DOM.
- Форматирования входных данных — Используйте компоненты форм Angular вместо этого.
- Фильтрации выходных данных — Используйте фильтры Angular вместо этого.
- Обмена кодом или состоянием между контроллерами — Используйте сервисы Angular вместо этого.
- Управления жизненным циклом других компонентов (например, для создания экземпляров сервисов).
Настройка начального состояния объекта $scope
Обычно при создании приложения вам нужно настроить начальное состояние объекта Angular $scope. Вы настраиваете начальное состояние scope, добавляя свойства к объекту $scope. Свойства содержат модель представления (модель, которая будет отображаться представлением). Все свойства $scope будут доступны шаблону в точке DOM, где зарегистрирован контроллер.
Следующий пример демонстрирует создание GreetingController, который добавляет свойство greeting, содержащее строку 'Hola!', к объекту $scope:
var myApp = angular.module('myApp',[]);
myApp.controller('GreetingController', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
}]);
Мы создаем модуль Angular, myApp, для нашего приложения. Затем мы добавляем конструктор функции контроллера в модуль с помощью метода .controller(). Это позволяет избежать размещения конструктора функции контроллера в глобальном scope.
$scope, предоставляемого Angular. Подробнее см. руководство по инъекции зависимостей. Мы прикрепляем наш контроллер к DOM с помощью директивы ng-controller. Свойство greeting теперь можно привязать к шаблону данными:
<div ng-controller="GreetingController">
{{ greeting }}
</div>
Добавление поведения к объекту Scope
Для реакции на события или выполнения вычислений в представлении мы должны предоставить поведение scope. Мы добавляем поведение в scope, добавляя методы к объекту $scope. Эти методы затем доступны для вызова из шаблона/представления.
Следующий пример использует контроллер для добавления метода, который удваивает число, к scope:
var myApp = angular.module('myApp',[]);
myApp.controller('DoubleController', ['$scope', function($scope) {
$scope.double = function(value) { return value * 2; };
}]);
После прикрепления контроллера к DOM, метод double может быть вызван в выражении Angular в шаблоне:
<div ng-controller="DoubleController">
Two times <input ng-model="num"> equals {{ double(num) }}
</div>
Как обсуждалось в разделе Концепции этого руководства, любые объекты (или примитивы), назначенные scope, становятся свойствами модели. Любые методы, назначенные scope, доступны в шаблоне/представлении и могут быть вызваны через выражения Angular и ng директивы обработчиков событий (например, ngClick).
Правильное использование контроллеров
В целом, контроллер не должен пытаться делать слишком много. Он должен содержать только бизнес-логику, необходимую для одного представления.
Наиболее распространенный способ сделать контроллеры более компактными — это инкапсулировать работу, которая не принадлежит контроллерам, в сервисы, а затем использовать эти сервисы в контроллерах через инъекцию зависимостей. Это обсуждается в разделах Инъекция зависимостей и Сервисы этого руководства.
Связывание контроллеров с объектами Angular Scope
Вы можете неявно связать контроллеры с объектами scope с помощью директивы ngController или $route service.
Чтобы проиллюстрировать, как работают компоненты контроллера в Angular, давайте создадим небольшое приложение с следующими компонентами:
- Шаблон template с двумя кнопками и простым сообщением
- Модель, состоящая из строки с именем
spice - Контроллер с двумя функциями, которые устанавливают значение
spice
Сообщение в нашем шаблоне содержит привязку к модели spice, которая по умолчанию установлена в строку "very". В зависимости от нажатой кнопки, модель spice устанавливается в chili или jalapeño, и сообщение автоматически обновляется благодаря привязке данных.
Что следует заметить в приведённом выше примере:
- Директива
ng-controllerиспользуется для (неявного) создания scope для нашего шаблона, и scope расширяется (управляется) контроллеромSpicyController. -
SpicyController— это просто обычная функция JavaScript. В качестве (необязательной) соглашения об именовании имя начинается с заглавной буквы и заканчивается на "Controller". - Назначение свойства
$scopeсоздает или обновляет модель. - Методы контроллера могут быть созданы путём прямого назначения scope (см. метод
chiliSpicy) - Методы и свойства контроллера доступны в шаблоне (как для элемента
<div>, так и для его дочерних элементов).
Методы контроллера также могут принимать аргументы, как показано в следующем варианте предыдущего примера.
Обратите внимание, что контроллер SpicyController теперь определяет только один метод, называемый spicy, который принимает один аргумент, называемый spice. Шаблон затем ссылается на этот метод контроллера и передает в нём строковую константу 'chili' в привязке для первой кнопки и свойство модели customSpice (привязанное к текстовому полю) во второй кнопке.
Обычно контроллеры прикрепляются на разных уровнях иерархии DOM. Поскольку директива ng-controller создаёт новый вложенный scope, мы получаем иерархию scope, унаследованную друг от друга. Scope $scope, полученный каждым контроллером, будет иметь доступ к свойствам и методам, определённым контроллерами выше по иерархии. Подробнее об унаследовании scope см. в разделе Понимание Scope.
Обратите внимание, как мы вложили три директивы ng-controller в наш шаблон. Это приведёт к созданию четырёх scope для нашего представления:
- Глобальный scope
- Scope
MainController, содержащий свойстваtimeOfDayиname - Scope
ChildController, который наследует свойствоtimeOfDay, но переопределяет (затеняет) свойствоnameиз предыдущего scope - Scope
GrandChildController, который переопределяет (затеняет) свойствоtimeOfDay, определённое вMainController, и свойствоname, определённое вChildController
Наследование работает с методами так же, как и со свойствами. Таким образом, во всех наших предыдущих примерах все свойства можно было заменить методами, которые возвращают строковые значения.
Тестирование контроллеров
Хотя есть много способов тестировать контроллер, одна из лучших соглашений, показанная ниже, включает инъекцию $rootScope и $controller:
Определение контроллера:
var myApp = angular.module('myApp',[]);
myApp.controller('MyController', function($scope) {
$scope.spices = [{"name":"pasilla", "spiciness":"mild"},
{"name":"jalapeno", "spiciness":"hot hot hot!"},
{"name":"habanero", "spiciness":"LAVA HOT!!"}];
$scope.spice = "habanero";
});
Тест контроллера:
describe('myController function', function() {
describe('myController', function() {
var $scope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
$scope = $rootScope.$new();
$controller('MyController', {$scope: $scope});
}));
it('should create "spices" model with 3 spices', function() {
expect($scope.spices.length).toBe(3);
});
it('should set the default value of spice', function() {
expect($scope.spice).toBe('habanero');
});
});
});
Если вам нужно протестировать вложенный контроллер, вы должны создать ту же иерархию scope в своём тесте, что и в DOM:
describe('state', function() {
var mainScope, childScope, grandChildScope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
mainScope = $rootScope.$new();
$controller('MainController', {$scope: mainScope});
childScope = mainScope.$new();
$controller('ChildController', {$scope: childScope});
grandChildScope = childScope.$new();
$controller('GrandChildController', {$scope: grandChildScope});
}));
it('should have over and selected', function() {
expect(mainScope.timeOfDay).toBe('morning');
expect(mainScope.name).toBe('Nikki');
expect(childScope.timeOfDay).toBe('morning');
expect(childScope.name).toBe('Mattie');
expect(grandChildScope.timeOfDay).toBe('evening');
expect(grandChildScope.name).toBe('Gingerbread Baby');
});
});
© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.5.11/docs/guide/controller