Spec-Zone.ru › Angular.js 1.7

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

В 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:

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. В качестве (необязательной) соглашения об именах имя начинается с заглавной буквы и заканчивается на "Controller".
  • Назначение свойства объекту $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–2018 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.7.8/docs/guide/controller

Spec-Zone.ru

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