Улучшить эту документациюКонтроллеры
В AngularJS контроллер определяется функцией JavaScript-конструктором, используемой для расширения объекта AngularJS Scope.
Контроллеры могут быть прикреплены к DOM различными способами. Для каждого из них AngularJS создаст новый объект контроллера, используя указанную функцию-конструктор контроллера:
- директива ngController. Создаётся новый дочерний объект Scope, доступный в качестве параметра для инъекции в конструктор функции контроллера как
$scope. - контроллер маршрута в определении $route.
- контроллер обычной директивы или компонентной директивы.
Если контроллер прикреплён с помощью синтаксиса controller as, то экземпляр контроллера будет назначен свойству в объекте Scope.
Используйте контроллеры для:
- Настройки начального состояния объекта
$scope. - Добавления поведения к объекту
$scope.
Не используйте контроллеры для:
- Манипулирования DOM — контроллеры должны содержать только бизнес-логику. Включение презентационной логики в контроллеры значительно ухудшает его тестируемость. В AngularJS для большинства случаев используются связывания данных и директивы для инкапсуляции ручного манипулирования DOM.
- Форматирования ввода — используйте контролы форм AngularJS вместо этого.
- Фильтрации вывода — используйте фильтры AngularJS вместо этого.
- Обмена кодом или состоянием между контроллерами — используйте службы AngularJS вместо этого.
- Управления жизненным циклом других компонентов (например, для создания экземпляров служб).
В целом, контроллер не должен пытаться сделать слишком много. Он должен содержать только бизнес-логику, необходимую для одного представления.
Наиболее распространённый способ сохранения компактности контроллеров — это инкапсуляция работы, которая не относится к контроллерам, в сервисы, а затем использование этих сервисов в контроллерах через инъекцию зависимостей. Это обсуждается в разделах Инъекции зависимостей и Сервисы этого руководства.
Настройка начального состояния объекта $scope
Как правило, при создании приложения вам необходимо настроить начальное состояние объекта AngularJS $scope. Начальное состояние объекта Scope устанавливается путём добавления свойств к объекту $scope. Свойства содержат модель представления (модель, которая будет отображаться представлением). Все свойства $scope будут доступны шаблону в том месте DOM, где зарегистрирован контроллер.
Следующий пример демонстрирует создание контроллера, который прикрепляет свойство greeting, содержащее строку 'Hola!', к объекту $scope.
var myApp = angular.module('myApp',[]);
myApp.controller('GreetingController', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
}]);
Мы создаём модуль AngularJS, myApp, для нашего приложения. Затем мы добавляем функцию-конструктор контроллера в модуль, используя метод .controller(). Это позволяет избежать попадания функции-конструктора контроллера в глобальную область видимости.
$scope, предоставляемой AngularJS. Подробнее см. руководство по инъекции зависимостей. Мы прикрепляем наш контроллер к 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 может быть вызван в выражении AngularJS в шаблоне:
<div ng-controller="DoubleController">
Two times <input ng-model="num"> equals {{ double(num) }}
</div>
Как обсуждалось в разделе Концепции этого руководства, любые объекты (или примитивы), назначенные объекту Scope, становятся свойствами модели. Любые методы, назначенные Scope, доступны в шаблоне/представлении и могут вызываться через выражения AngularJS и ng (например, ngClick).
Для дальнейшего иллюстрации того, как работают компоненты контроллера в AngularJS, давайте создадим небольшое приложение с указанными компонентами:
- Шаблон шаблона с двумя кнопками и простым сообщением
- Модель, состоящая из строки с именем
spice - Контроллер с двумя функциями, которые устанавливают значение
spice
Сообщение в нашем шаблоне содержит привязку к модели spice, которая по умолчанию устанавливается в строку «very». В зависимости от нажатой кнопки, модель spice устанавливается в chili или jalapeño, и сообщение автоматически обновляется с помощью привязки данных.
Следует обратить внимание на примеры:
- Директива
ngControllerиспользуется для (неявного) создания области видимости для нашего шаблона, и область видимости расширяется (управляется) контроллеромSpicyController. SpicyController— это просто обычная функция JavaScript. В качестве (необязательного) соглашения об именовании имя начинается с заглавной буквы и заканчивается словом «Контроллер».- Присвоение свойства объекту
$scopeсоздаёт или обновляет модель. - Методы контроллера могут быть созданы путём прямого назначения в Scope (см. метод
chiliSpicy). - Методы и свойства контроллера доступны в шаблоне (как для элемента
<div>, так и для его дочерних элементов).
Методы контроллера также могут принимать аргументы, как показано в следующем варианте предыдущего примера.
Обратите внимание, что контроллер SpicyController теперь определяет только один метод под названием spicy, который принимает один аргумент под названием spice. Шаблон затем обращается к этому методу контроллера и передает в нём строковую константу 'chili' в привязку для первой кнопки и свойство модели customSpice (связанное с текстовым полем) во второй кнопке.
Контроллеры часто прикрепляются на разных уровнях иерархии DOM. Так как директива ng-controller создаёт новый дочерний объект Scope, мы получаем иерархию объектов Scope, наследующих друг от друга. Объект Scope, который получает каждый контроллер, имеет доступ к свойствам и методам, определённым контроллерами на более высоких уровнях иерархии. Подробнее об иерархии Scope см. в разделе Понимание объектов Scope.
Обратите внимание, как мы вложили три директивы ng-controller в наш шаблон. Это приведёт к созданию четырёх областей видимости для нашего представления:
- Корневая область видимости
- Область видимости
MainController, которая содержит свойстваtimeOfDayиname - Область видимости
ChildController, которая наследует свойствоtimeOfDay, но переопределяет (затеняет) свойствоnameиз предыдущей области видимости - Область видимости
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');
});
});
});
Если вам необходимо протестировать вложенный контроллер, необходимо создать в вашем тесте такую же иерархию областей видимости, которая существует в 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–2018 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.6.9/docs/guide/controller