Улучшить эту страницуКонтроллеры
В Angular, Контроллер — это JavaScript-функция-конструктор, используемая для расширения объекта Angular Scope.
Когда Контроллер прикрепляется к DOM через директиву ng-controller, Angular создаст новый объект Контроллера, используя указанную функцию-конструктор Контроллера. Новый дочерний scope будет доступен как параметр для инъекции в функцию-конструктор Контроллера как $scope.
Используйте контроллеры для:
- Настройки начального состояния объекта
$scope. - Добавления поведения к объекту
$scope.
Не используйте контроллеры для:
- Манипулирования DOM — Контроллеры должны содержать только бизнес-логику. Размещение любой презентационной логики в Контроллерах существенно влияет на его тестируемость. Angular предоставляет привязки данных для большинства случаев и директивы для инкапсуляции ручных манипуляций с DOM.
- Форматирования ввода — Используйте ангулярные компоненты форм вместо этого.
- Фильтрации вывода — Используйте ангулярные фильтры вместо этого.
- Обмена кодом или состоянием между контроллерами — Используйте ангулярные сервисы вместо этого.
- Управления жизненным циклом других компонентов (например, для создания экземпляров сервисов).
Настройка начального состояния объекта $scope
Обычно, при создании приложения, необходимо настроить начальное состояние объекта Angular $scope. Начальное состояние scope устанавливается путем прикрепления свойств к объекту $scope. Свойства содержат модель представления (модель, которая будет представлена видом). Все свойства $scope будут доступны шаблону в той части DOM, где зарегистрирован Контроллер.
Следующий пример демонстрирует создание контроллера, который прикрепляет свойство greeting, содержащее строку 'Hola!', к объекту $scope:
var myApp = angular.module('myApp',[]);
myApp.controller('GreetingController', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
}]);
Мы создаем модуль Angular, myApp, для нашего приложения. Затем мы добавляем функцию-конструктор контроллера в модуль с помощью метода .controller(). Это предотвращает попадание функции-конструктора контроллера в глобальную область видимости.
$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 может быть вызван в ангулярском выражении в шаблоне:
<div ng-controller="DoubleController">
Two times <input ng-model="num"> equals {{ double(num) }}
</div>
Как обсуждалось в разделе «Концепции» этого руководства, любые объекты (или примитивы), присваиваемые scope, становятся свойствами модели. Любые методы, присваиваемые scope, доступны в шаблоне/представлении и могут вызываться с помощью ангулярских выражений и обработчиков событий 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" или "Controller". - Присвоение свойства объекту
$scopeсоздает или обновляет модель. - Методы контроллера могут быть созданы путем прямого присвоения scope (см. метод
chiliSpicy). - Методы и свойства контроллера доступны в шаблоне (для элемента
<div>и его дочерних элементов).
Методы контроллера также могут принимать аргументы, как показано в следующем варианте предыдущего примера.
Обратите внимание, что контроллер SpicyController теперь определяет только один метод, называемый spicy, который принимает один аргумент, называемый spice. Затем шаблон ссылается на этот метод контроллера и передает строковый констант 'chili' в привязке для первой кнопки и свойство модели customSpice (привязанное к текстовому полю) во второй кнопке.
Контроллеры часто прикрепляются на разных уровнях иерархии DOM. Поскольку директива ng-controller создает новый дочерний scope, мы получаем иерархию scope, наследующую друг от друга. Scope, который получает каждый контроллер, будет иметь доступ к свойствам и методам, определённым контроллерами выше по иерархии. Более подробную информацию о наследовании scope см. в разделе Понимание Scope.
Обратите внимание, как мы вложены три директивы ng-controller в наш шаблон. Это приведет к созданию четырёх scope для нашего представления:
- Глобальный scope
- Scope
MainController, содержащий свойстваtimeOfDayиname - Scope
ChildController, который наследует свойствоtimeOfDay, но переопределяет (скрывает) свойствоnameиз предыдущего - 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.2.32/docs/guide/controller