Где должно храниться состояние модели в Angular.js

Я нахожу использование Angular моделей, запутывающих. Angular, похоже, использует подход, который может быть любой моделью - I.E. Angular не включает явный класс модели, и вы можете использовать ванильные объекты JavaScript в качестве моделей.

В почти каждом примере Angular, который я видел, модель является фактически объектом, созданным вручную или возвращенным из вызова API через Resource. Поскольку почти каждый пример Angular, который я рассмотрел, прост, обычно данные модели, хранящиеся в области $scope в контроллере, и любое состояние, относящееся к модели, например, выбор, также хранятся в области $scope в контроллере. Это отлично подходит для простых приложений/примеров, но это похоже на упрощение, когда приложения становятся более сложными. Состояние модели, хранящееся в контроллере, рискует стать контекстуальным и потеряться, если контекст изменяется, например; Контроллер, хранящий selectedGallery и selectedPhoto, может хранить только глобальные selectedImage, а не selectedPhoto для каждой галереи. В такой ситуации использование контроллера для каждой галереи может свести на нет эту проблему, но будет казаться расточительным и, вероятно, неуместным и ненужным с точки зрения пользовательского интерфейса.

Angular определение моделей кажется ближе к тому, что я бы рассматривал VO/DTO, который является немым объектом, переданным между сервером и клиентом. Мой инстинкт заключается в том, чтобы обернуть такой объект в то, что я хотел бы рассмотреть Модель - класс, который поддерживает состояние, относящееся к DTO/VO (например, выбор), предлагает мутаторы, необходимые для управления DTO/VO, и уведомляет остальную часть внесение изменений в базовые данные. Очевидно, что эта последняя часть хорошо позабочена связями Angular, но я по-прежнему вижу сильную прецеденцию для первых двух обязанностей.

Однако я не видел этот шаблон, используемый в примерах, на которые я смотрел, но я также не видел, что я рассматриваю как масштабируемую альтернативу. Angular, кажется, неявно препятствует использованию Сервисов в качестве моделей, применяя Singletons (я знаю, что есть способы обойти это, но они не кажутся широко используемыми или одобренными).

Итак, как я должен сохранять состояние в данных модели?

[Edit] Второй ответ в этот вопрос интересен и близок к тому, что я сейчас использую.

Ответ 1

Состояние (и модели) хранятся в $scope

$scope Angular объект хранения данных. Он аналогичен базе данных. $scope не является моделью, но вы можете хранить модели в $scope.

Каждый $scope имеет родительскую область $scope, вплоть до $rootScope, образующую древовидную структуру, которая свободно отражает ваш DOM. Когда вы вызываете директиву, которая требует новой $scope, такой как ng-controller, новый объект области $будет создан и добавлен в дерево.

Объекты области

$связаны с использованием прототипического наследования. Это означает, что если вы добавите модель на более высоком уровне в дерево, она будет доступна для всех нижних уровней. Это феноменально мощная функция, которая делает иерархию $scope почти прозрачной для автора шаблона.

Контроллеры инициализируют $scope

Цель контроллера - инициализировать $scope. Один и тот же контроллер может инициализировать множество объектов $scope в разных частях страницы. Контроллер создается, настраивает объект $scope и затем выходит. Вы можете использовать один и тот же контроллер для инициализации многих областей $в разных частях страницы.

В случае вашей галереи изображений у вас будет контроллер изображения, который вы затем примените к каждой части DOM, которую хотите стать галереей, с помощью директивы ng-controller. Эта часть страницы получит свою собственную область $scope, которую вы использовали бы для хранения атрибута selectedPhoto.

Прототипные области

$scope наследует от своего родителя, используя обычное старое прототипическое наследование вплоть до $rootScope, поэтому вы можете хранить свои объекты в любом месте иерархии, что имеет смысл. Вы получаете дерево объектов $scope, которые примерно связаны с вашей текущей DOM. Если ваш DOM изменяется, для вас создаются новые объекты $scope.

$scope - просто простой объект JavaScript. Это не более бесполезно для создания нескольких объектов $scope, чем для создания массива с несколькими объектами currentImage. Это разумный способ организовать ваш код.

Таким образом, Angular устраняет старую проблему "Где я храню свои данные", которую мы часто находим в JavaScript. Это источник одного из действительно больших приростов производительности, которые мы получаем от Angular.

Получены глобальные данные (например, userId)? сохраните его на $rootScope. Получены локальные данные (например, currentImage в галерее, где есть несколько экземпляров галереи)? Храните его в объекте $scope, принадлежащем этой галерее.

$scope автоматически предоставляется вам в правильной части шаблона.

Angular модели тонкие

Исходя из фона Rails, где мы подчеркиваем модели жира и тощие контроллеры, я обнаружил, что Angular "едва ли" модели удивляют. На самом деле, ставя много бизнес-логики в вашу модель, часто приводит к проблемам на линии, как мы иногда видим с моделью пользователя в Rails, которая, если вы не будете осторожны, будет расти, пока она не станет недостижимой.

Модель Angular - это просто объект JavaScript или примитив.

Любой объект может быть моделью. Модели обычно определяются с использованием JSON в контроллере или AJAXed с сервера. Модель может быть объектом JSON или может быть просто строкой, массивом или даже числом.

Конечно, вам нечего мешать добавлять дополнительные функции в вашу модель и хранить их в объекте JSON, если хотите, но это будет портирование в парадигме, которая не подходит для Angular.

Angular объекты обычно являются репозиториями данных, а не функциями.

Модель на переднем конце не является реальной моделью

Конечно, модель, которую вы держите на клиенте, не является реальной моделью. Ваша реальная модель, ваш единственный источник правды живет на сервере. Мы синхронизируем его с помощью API, но если конфликт между двумя моделью в вашей базе данных, очевидно, является окончательным победителем.

Это дает вам конфиденциальность для таких вещей, как коды скидок и т.д. Модель, которую вы находите в своем интерфейсе, представляет собой синхронизированную версию общедоступных свойств реальной модели, которая является удаленной.

Бизнес-логика может жить в сервисах.

Предположим, вы хотите написать метод, чтобы что-то сделать с вашей моделью, синхронизировать его или, например, проверить его. В других рамках у вас может возникнуть соблазн расширить вашу модель с помощью метода для этого. В Angular вы с большей вероятностью напишите сервис.

Службы - одноэлементные объекты. Как и любой другой объект JavaScript, вы можете помещать в них функции или данные. Angular поставляется с кучей встроенных сервисов, таких как $http. Вы можете создавать свои собственные и использовать инъекции зависимостей, чтобы автоматически предоставлять их своим контроллерам.

Служба может содержать методы для взаимодействия с RESTful API, например, для проверки ваших данных или любой другой работы, которая вам может понадобиться.

Услуги не являются моделями

Конечно, вы не должны использовать службы в качестве моделей. Используйте их как объекты, которые могут делать вещи. Иногда они делают материал для вашей модели. Это другой способ мышления, но работоспособный.

Ответ 2

Прежде всего, не стоит забывать, что Angular - это веб-инфраструктура, и если вы "сохраняете свое состояние" исключительно в объекте, он не сможет выжить, обновляя обновление в своем браузере. Поэтому выяснение того, как сохранить состояние данных модели в веб-приложении, означает выяснение того, как вы собираетесь продолжать его, чтобы ваш код функционировал в среде браузера.

Angular упрощает сохранение состояния, используя:

  • Вызов ресурса RESTful $
  • URL-адрес, представляющий экземпляр вашей модели.

В вашем простом примере сохранение пользовательских действий, таких как selectedGallery и selectedPhoto, может быть представлено с использованием URL-адреса с чем-то вроде:

// List of galleries
.../gallery

// List of photos in a gallery
.../gallery/23

// A specific photo
.../gallery/23/photo/2

URL-адрес имеет решающее значение, поскольку он позволяет вашему пользователю перемещаться по истории браузера с помощью кнопок back и forward. Если вы хотите поделиться этим состоянием с другой частью вашего приложения, веб-приложение предоставляет множество методов для этого, используя cookie/localStorage, скрытый фрейм/поля или даже сохраняя его на своем сервере.

После того, как вы определили свою стратегию о том, как упорствовать в разных состояниях вашего приложения, должно быть проще решить, хотите ли вы получить доступ к этой сохраненной информации, используя одноэлементный объект, предоставленный .service, или экземпляр через .factory.

Ответ 3

Angular не имеет мнения о том, как вы храните то, что вы называете "объектами модели". Контроллер Angular $scope существует исключительно как "модель представления" для управления вашим пользовательским интерфейсом. Я предлагаю отделить эти два понятия от вашего кода.

Если вы хотите получить уведомление об изменении области видимости Angular ($watch), вы можете использовать объект области видимости для хранения данных модели, если хотите (var myScope = $rootScope.$new()). Просто не используйте тот же объект области, к которому привязан ваш интерфейс.

Я рекомендую писать пользовательские сервисы с этой целью. Таким образом, поток данных выглядит следующим образом:

AJAX → Пользовательская услуга → Объект области модели → Контроллер → Объект области пользовательского интерфейса → DOM

Или это:

AJAX → Пользовательские сервисы → Обычные старые объекты JavaScript → Контроллер → Объект области пользовательского интерфейса → DOM