我发现角的使用模式混乱。 角似乎采取一种模式可以是任何你喜欢的方式 - IE角不包括一个明确的模型类,你可以使用香草JavaScript对象的模型。
几乎在每一个角度的例子,我所看到的,该模型实际上是一个对象,无论是手工制作,或者通过资源的API调用返回。 因为几乎我看了每一个角例子很简单,通常是存储在$范围模型数据在控制器和模型相关的任何状态,例如选择,也存储在控制器中的$范围。 这工作正常进行简单的应用/例子,但是这似乎是一个过于简单化,当应用程序变得更加复杂。 存储在控制器模型状态是在成为上下文,并且如果环境的变化,例如被丢失的风险; A控制器存储selectedGallery
和selectedPhoto
只能存储全球selectedImage
,不是selectedPhoto
每画廊。 在这种情况下,使用每库控制器可能会否定这个问题,但似乎从UI的角度浪费和可能不适当和不必要的。
角的车型定义似乎接近我会考虑VO / DTO是服务器和客户端之间传递一个愚蠢的对象。 我的直觉是什么,我会考虑一个模型来包装这样的目标 - 维护状态有关的DTO / VO(如选择)一类,根据需要操纵DTO / VO提供存取器,并通知休息应用程序更改为基础数据的。 显然,这最后一部分是很好的照顾,由角的绑定,但我还是看到了强烈的用例前两个职责。
但是我还没有看到在我看过的例子中使用这种模式,但也没看到什么,我会考虑一个可伸缩的替代品。 角似乎使用各项服务模型通过强制执行单身人士含蓄地鼓励(我知道有很多方法可以解决这个问题,但他们似乎没有得到广泛使用或批准)。
所以,我应该怎么对模型的数据来保持状态?
[编辑]在第二个答案这个问题很有趣,而且靠近什么我目前使用到。
国家(和模型)存储在$范围
$范围角度的数据存储对象。 它类似于一个数据库。 $范围本身不是模式,但你可以存储模型$范围。
每个$范围有一个父$范围,一路高达$ rootScope形成树状结构松散镜像您的DOM。 当你调用这需要一个新的$范围,如NG控制器一个指令,一个新的$范围对象将被创建并添加到树。
$范围对象是使用原型继承连接。 这意味着,如果你在树中的较高级别添加一个模型,它会提供给所有的较低水平。 这是一个惊人强大的功能,这使得$范围层次几乎是透明的模板作者。
控制器初始化$范围
控制器的目的是初始化$范围 。 相同的控制器可以初始化页面的不同地区的许多$范围的对象。 该控制器被实例化,树立$范围对象,然后退出。 您可以使用相同的控制器在页面的不同部分进行初始化许多$范围。
在您的图片库的情况下,你将有一个imageGallery控制器,那么您需要适用于您想使用NG-控制器指令画廊DOM的每一个部分。 页面的那部分将获得它自己的$范围,其中你会使用存储selectedPhoto属性。
原型范围
$范围使用普通的旧的原型继承高达$ rootScope一路继承其父,这样你就可以在有意义的层次结构中的任意位置存储你的对象。 你得到$范围对象的树,大约涉及到当前的DOM。 如果你的DOM的变化,会为您创建新的$范围的对象的要求。
$范围仅仅是一个普通的JavaScript对象。 这是没有更多的浪费,以创建多个$范围的对象比起来,创建具有多个currentImage对象的数组。 这是将代码组织一个明智的方式。
这样的角摒弃了旧的“我在哪里存储我的数据”的问题,我们经常会发现在JavaScript中。 这是非常大的生产率的提高,我们从角得到的一个来源。
得到了全局数据(如用户ID)? 其存储在$ rootScope。 有本地数据(例如,在有多个画廊实例一个画廊currentImage)? 它存储属于该画廊在$范围对象。
$范围是在模板的正确部分自动提供给您。
角型号薄
从Rails的背景下,我们强调的脂肪模型,瘦控制器来了,我发现了角的“几乎没有”模型令人惊讶。 事实上,投入了大量的业务逻辑的模型往往导致了线的问题,因为我们有时在Rails的用户模型,如果你不小心,将增长,直到它变得难以维护看到。
角模型只是一个JavaScript对象或原语。
任何对象可以是一个模型。 模型是在所述控制器使用JSON通常定义,或者从服务器中AJAXed。 一个模型可能是一个JSON对象,或者可能只是一个字符串,数组,甚至一个数字。
当然,没有什么阻止你添加额外的功能,你的模型,并将它们存储在JSON对象,如果您想要的,但这在并不真正适合与角的范例被移植。
角对象通常数据,而不是功能的库。
在前端的模型是不是真正的模型
当然,你在客户端上保持模型是不是真正的模式。 您的实际型号,单一数据源居住在服务器上。 我们使用同步的API,但如果有两者之间的冲突在你的数据库模型显然是最终的胜利者。
这给你的隐私的东西像优惠码等,你在你的前端找到该模型是真实模型,这是远程的公共属性的同步版本。
业务逻辑可以住在服务。
说你要写信给做一些模型的方法,进行同步,或验证它的例子。 在其他框架你可能会与要做到这一点的方法扩展你的模型。 在角,你会更容易编写的服务。
服务是单一对象。 像任何其他JavaScript对象,你可以把功能或数据在其中。 角有自带的服务一堆,如$ HTTP。 你可以建立自己的,并使用依赖注入来自动将它们提供给您的控制器。
服务可能包含方法去跟一个RESTful API,例如,或以验证您的资料,或任何其他的工作,你可能需要做。
服务是不是模型
当然,你不应该使用服务模式。 使用它们作为可以做的东西的对象。 有时他们做的东西给你的模型。 这是一种不同的思维方式,但一个可行的一个。
First of all, let's not forget that Angular is a web based framework and if you "keep your state" solely in an object, it will not survive user hitting refresh on their browser. Therefore, figuring out how to keep state of Model data in a web based application means figuring out how you are going to persist it so that your code will function in a browser environment.
Angular makes it really easy for you to persist your state using:
- A call to a RESTful $resource
- An URL representing an instance of your model
In your simple example, the storing of user actions such as selectedGallery
and selectedPhoto
can be represented using URL with something like:
// List of galleries
.../gallery
// List of photos in a gallery
.../gallery/23
// A specific photo
.../gallery/23/photo/2
The URL is critical because it allow your user to navigate the browser history using back
and forward
buttons. If you wish to share this state with other part of your application, web application provide wealth of methods for you accomplish that using cookie/localStorage, hidden frame/fields or even storing it in your server.
Once you defined your strategy on how to persist different state of your application, it should be easier to decide if you wish to access these persisted info using a singleton object as provided by .service
or an instance via .factory
.
你如何存储你所说的“模型对象”的角度上没有意见。 该角控制器$scope
为“视图模型”管理UI的目的而存在。 我建议在你的代码分离这两个概念。
如果你想要的角度范围变更的通知(在精密$watch
),您可以使用范围对象来存储你的模型,如果你想( var myScope = $rootScope.$new()
只要不使用到你的UI绑定到的范围对象。
我建议为此编写定制服务。 因此,数据流是这样的:
AJAX - >自定义服务 - >模型范围对象 - >控制器 - > UI范围对象 - > DOM
或这个:
AJAX - >自定义服务 - >普通老式JavaScript对象 - >控制器 - > UI范围对象 - > DOM