Spec-Zone.ru › Angular.js 1.4

Улучшить эту документациюКонтроллеры

В 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, где зарегистрирован контроллер.

Следующий пример демонстрирует создание контроллера, который прикрепляет свойство 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 может быть вызван в выражении 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.

Чтобы проиллюстрировать, как работают компоненты контроллеров в Angular, давайте создадим небольшое приложение с следующими компонентами:

  • Шаблон template с двумя кнопками и простым сообщением
  • Модель, состоящая из строки с именем spice
  • Контроллер с двумя функциями, которые устанавливают значение spice

Сообщение в нашем шаблоне содержит привязку к модели spice, которая по умолчанию устанавливается в строку «very». В зависимости от нажатой кнопки, модель spice устанавливается в chili или jalapeño, и сообщение автоматически обновляется за счет привязки данных.

Следует обратить внимание на пример выше:

  • Директива ng-controller используется для (неявного) создания объекта scope для нашего шаблона, и объект scope расширяется (управляется) контроллером SpicyController.
  • SpicyController — это просто обычная функция JavaScript. В качестве (необязательной) соглашения об именах имя начинается с заглавной буквы и заканчивается «Контроллер».
  • Присвоение свойства объекту $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
  • Объект 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.4.14/docs/guide/controller

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API