状态(和模型)存储在 $scope
$scope 是 Angular 的数据存储对象。它类似于数据库。$scope 本身不是模型,但您可以将模型存储在 $scope 中。
每个 $scope 都有一个父 $scope,一直到 $rootScope 形成一个松散地镜像你的 DOM 的树结构。当您调用需要新 $scope 的指令时,例如 ng-controller,将创建一个新的 $scope 对象并将其添加到树中。
$scope 对象使用原型继承连接。这意味着,如果您在树中的较高级别添加模型,则所有较低级别都可以使用该模型。这是一个非常强大的功能,它使 $scope 层次结构对模板作者几乎是透明的。
控制器初始化 $scope
控制器的目的是初始化 $scope。同一个控制器可以在页面的不同部分初始化许多 $scope 对象。控制器被实例化,设置 $scope 对象然后退出。您可以使用同一个控制器在页面的不同部分初始化许多 $scope。
对于您的图片库,您将拥有一个 imageGallery 控制器,然后您将使用 ng-controller 指令将其应用于您希望成为图库的 DOM 的每个部分。页面的该部分将获得它自己的 $scope,您将使用它来存储 selectedPhoto 属性。
原型范围
$scope 使用普通的旧原型继承从其父级继承一直到 $rootScope,因此您可以将对象存储在层次结构中有意义的任何位置。你会得到一棵与你当前的 DOM 大致相关的 $scope 对象树。如果您的 DOM 发生更改,则会根据需要为您创建新的 $scope 对象。
$scope 只是一个普通的 JavaScript 对象。创建多个 $scope 对象并不比创建一个包含多个 currentImage 对象的数组更浪费。这是组织代码的明智方式。
通过这种方式,Angular 消除了我们在 JavaScript 中经常遇到的“我在哪里存储我的数据”的老问题。这是我们从 Angular 获得的真正巨大的生产力收益之一。
有全局数据(例如,用户 ID)?将其存储在 $rootScope 上。有本地数据(例如,在有多个画廊实例的画廊中的 currentImage)?将其存储在属于该画廊的 $scope 对象上。
$scope 会在模板的正确部分自动提供给您。
Angular 模型很薄
来自我们强调胖模型和瘦控制器的 Rails 背景,我发现 Angular 的“几乎没有”模型令人惊讶。事实上,在模型中放置大量业务逻辑通常会导致问题,正如我们有时在 Rails 中看到的那样,如果您不小心,它会不断增长,直到变得无法维护。
角度模型只是一个 JavaScript 对象或原语。
任何对象都可以是模型。模型通常在控制器中使用 JSON 定义,或者从服务器 AJAX 中定义。模型可能是一个 JSON 对象,也可能只是一个字符串、数组,甚至是一个数字。
当然,如果您愿意,没有什么可以阻止您向模型添加额外的函数并将它们存储在 JSON 对象中,但这将移植到一个并不真正适合 Angular 的范例中。
Angular 对象通常是数据的存储库,而不是函数。
前端的模型不是真实模型
当然,您持有的客户模型不是真正的模型。您的实际模型,您的单一事实来源存在于服务器上。我们使用 API 对其进行同步,但如果两者之间存在冲突,则数据库中的模型显然是最终的胜利者。
这为您提供了折扣代码等内容的隐私。您在前端找到的模型是真实模型的公共属性的同步版本,它是远程的。
业务逻辑可以存在于服务中。
例如,假设您想编写一个方法来对模型执行某些操作、同步或验证它。在其他框架中,您可能很想用一种方法来扩展您的模型。在 Angular 中,您更有可能编写服务。
服务是单例对象。像任何其他 JavaScript 对象一样,您可以将函数或数据放入其中。Angular 附带了一堆内置服务,例如 $http。您可以构建自己的,并使用依赖注入自动将它们提供给您的控制器。
例如,服务可能包含与 RESTful API 对话、验证数据或您可能需要做的任何其他工作的方法。
服务不是模型
当然,您不应该将服务用作模型。将它们用作可以做事的对象。有时他们会对你的模型做一些事情。这是一种不同的思维方式,但一种可行的方式。