Улучшить эту документациюКонтроллеры
В 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, и сообщение автоматически обновляется с помощью привязки данных.
Следует обратить внимание на пример выше:
- Директива
ng-controllerиспользуется для (неявного) создания области видимости для нашего шаблона, и область видимости расширяется (управляется) контроллеромSpicyController. -
SpicyController— это просто обычная функция JavaScript. В качестве (необязательной) соглашения об именовании имя начинается с большой буквы и заканчивается «Контроллер». - Назначение свойства объекту
$scopeсоздает или обновляет модель. - Методы контроллера могут быть созданы путем прямого назначения в scope (см. метод
chiliSpicy). - Методы и свойства контроллера доступны в шаблоне (как для элемента
<div>, так и для его дочерних элементов).
Методы контроллера также могут принимать аргументы, как показано в следующей модификации предыдущего примера.
Обратите внимание, что контроллер SpicyController теперь определяет только один метод под названием spicy, который принимает один аргумент под названием spice. Шаблон затем ссылается на этот метод контроллера и передает строковую константу 'chili' в привязку для первой кнопки и свойство модели customSpice (связанное с текстовым полем) во второй кнопке.
Часто контроллеры прикрепляются на разных уровнях иерархии DOM. Поскольку директива ng-controller создает новую дочернюю область видимости, мы получаем иерархию областей видимости, которые наследуют друг от друга. Объект $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–2020 Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
https://code.angularjs.org/1.8.2/docs/guide/controller