在Angular.js中,模型状态应该存储在哪里?

17 浏览
0 Comments

在Angular.js中,模型状态应该存储在哪里?

我发现Angular对模型的使用很困惑。Angular似乎采取的是模型可以是任何你喜欢的东西的方法 - 也就是说,Angular没有包含一个显式的模型类,你可以使用普通的JavaScript对象作为模型。\n在我看过的几乎每一个Angular示例中,模型实际上都是一个对象,可以手动创建,也可以通过API调用返回的资源对象。因为我看过的几乎每一个Angular示例都很简单,通常模型数据存储在控制器的$scope上,与模型相关的任何状态,例如选择状态,也存储在控制器的$scope上。这对于简单的应用/示例来说很好,但是当应用变得更加复杂时,这似乎过于简化了。存储在控制器中的模型状态可能会变得上下文相关,并且在上下文变化时可能会丢失,例如:一个控制器存储selectedGalleryselectedPhoto,只能存储全局selectedImage,而不能存储每个图库的selectedPhoto。在这种情况下,使用一个控制器来处理每个图库可能会消除这个问题,但从UI的角度来看,这似乎是浪费和不合适的。\nAngular对模型的定义似乎更接近我认为的VO/DTO,即在服务器和客户端之间传递的一个简单对象。我的直觉是将这样的对象包装在我认为的模型中 - 一个维护与DTO/VO相关的状态(如选择状态)、根据需要提供修改DTO/VO的方法,并通知应用程序底层数据更改的类。显然,最后一部分由Angular的绑定很好地处理了,但我仍然认为前两个责任有很强的用例。\n然而,在我看过的示例中,我并没有真正看到这种模式的使用,但我也没有看到我认为的可扩展的替代方案。Angular似乎通过强制使用单例(我知道有办法绕过这个限制,但似乎并不常用或被认可)隐含地不鼓励将服务用作模型。\n那么,我应该如何保持模型数据的状态?\n[编辑]在这个问题的第二个答案很有趣,也接近我目前使用的方式。

0
0 Comments

Angular.js中模型状态应该存储在哪里的问题的出现原因是Angular.js不关心如何存储你所称之为“模型对象”的东西。 Angular控制器$scope仅作为管理UI的“视图模型”存在。建议在代码中将这两个概念分开。

如果您想要使用Angular作用域更改通知($watch)的便利性,可以使用作用域对象来存储模型数据(var myScope = $rootScope.$new())。只是不要使用与您的UI绑定的相同作用域对象。

我建议编写自定义服务来实现这一目标。因此,数据流如下:

AJAX --> 自定义服务 --> 模型作用域对象 --> 控制器 --> UI作用域对象 --> DOM

或者如下:

AJAX --> 自定义服务 --> 平常的JavaScript对象 --> 控制器 --> UI作用域对象 --> DOM

我已经分离了这些概念,这正是我提出这个问题的原因。处理模型状态的标准Angular方式似乎是将其存储在这个视图模型中,这正是我感到不舒服的地方。创建一个新的作用域对我来说不是一个好的解决方案。这感觉像是对作用域的误用。

0
0 Comments

在Angular.js中,如何存储模型状态是一个需要解决的问题。因为Angular是一个基于Web的框架,如果将状态仅存储在对象中,当用户刷新浏览器时状态将无法保留。因此,需要找出如何持久化模型数据的方法,以确保代码在浏览器环境中正常运行。

Angular提供了简单的方法来持久化状态,包括:

1. 使用RESTful $resource进行调用

2. 使用表示模型实例的URL

在简单的示例中,可以使用类似以下URL的方式存储用户操作的状态,如selectedGalleryselectedPhoto

// 图库列表
.../gallery
// 图库中的照片列表
.../gallery/23
// 特定的照片
.../gallery/23/photo/2

URL的关键之处在于它允许用户使用浏览器的backforward按钮导航浏览历史记录。如果希望与应用程序的其他部分共享此状态,Web应用程序提供了许多方法,如使用cookie/localStorage、隐藏的frame/fields,甚至存储在服务器上。

一旦确定了持久化应用程序不同状态的策略,就可以更容易地决定是使用.service提供的单例对象来访问这些持久化信息,还是使用.factory提供的实例对象。

这很有道理,我完全同意应该通过路径/查询字符串来跟踪应用程序状态,但这显然是应用程序状态的一种展示,而不是存储方式。URL栏是模型和视图的奇怪组合,但它最终反映了内部应用程序状态或促使该状态发生变化。REST应用程序本身仍然需要一种方法来在内部跟踪此状态,并在服务/模型上共享访问似乎是正确的解决方案。

此外,.service和.factory都返回单例服务(这非常令人困惑)。

实际上,这不是正确的。.service返回单例,但你可以使用.factory创建实例。我找一个示例,稍后将在此评论中更新。

谢谢,我同意这是可能的,但明显并没有将其作为.factory的常见用法来推广。

我明白你的观点。我同意你的观点,Angular的文档指出"最后,需要认识到所有的Angular服务都是应用程序的单例",但我认为这是文档编写不当。我个人使用.service来创建单例对象,而使用.factory返回可实例化的对象。

如果你有使用factory生成实例的示例,可以分享一下吗?

在这里:[plnkr.co/edit/9UMI1zeMRArefqgvC8Ch?p=preview](plnkr.co/edit/9UMI1zeMRArefqgvC8Ch?p=preview)。我试图尽可能简单地传达观点。

有意思...虽然你可以这样做,但你应该这样做吗?现在,使用该工厂的依赖注入方式与其他不同--也就是说,由于你返回的是一个函数(对象),而不是一个对象(即{}),你必须使用new关键字来创建一个实例。这意味着你无法使用正常的依赖注入语法将该实例与其他实体共享。我认为这会对其他可能使用你的代码的Angular开发人员造成困惑。

我有意返回一个可实例化的函数,以便new关键字表明这个服务不应该与其他实体共享。例如,我在控制器中传递$scope实例化ui.bootstrap.alert的包装器。当我以后需要显示警报时,我只需调用alert.success("Ok")。也就是说,我同意调用者在何时使用new并不清楚,但这确实取决于使用服务的用户了解如何使用服务。

我确实意识到使用new是令人困惑的,但它是对我来说,提醒我调用的服务不应该共享。然而,如果问题纯粹是语法方面的,你也可以返回一个对象,即在.factory中调用new。我更新了plunker以说明如何做到这一点。

0
0 Comments

在Angular.js中,模型状态应该存储在哪里是一个常见的问题。$scope是Angular的数据存储对象,类似于数据库。每个$scope都有一个父$scope,一直到$rootScope,形成一个树状结构,与DOM大致相对应。当调用需要一个新$scope的指令(如ng-controller)时,将创建一个新的$scope对象并添加到树中。$scope对象使用原型继承连接,这意味着如果在树的较高级别添加一个模型,它将对所有较低级别可用。这是一个非常强大的功能,使得$scope层次对于模板作者几乎是透明的。

控制器的目的是初始化$scope。同一个控制器可以在页面的不同部分初始化多个$scope对象。控制器被实例化,设置$scope对象,然后退出。您可以使用同一个控制器在页面的不同部分初始化多个$scope。

$scope从其父类继承,一直到$rootScope,因此您可以将对象存储在任何合理的层次结构上。您可以获得一个与当前DOM大致对应的$scope对象树。如果DOM发生更改,将根据需要为您创建新的$scope对象。$scope只是一个普通的JavaScript对象,创建多个$scope对象与创建具有多个currentImage对象的数组没有什么区别,这是一种合理的代码组织方式。Angular摆脱了JavaScript中的“数据存储在哪里”的问题,这是我们从Angular中获得的真正的生产力提升之一。全局数据(例如userId)可以存储在$rootScope上,本地数据(例如在多个gallery实例中存在多个gallery时的currentImage)可以存储在属于该gallery的$scope对象上。

Angular的模型非常简洁,一个Angular模型只是一个JavaScript对象或原语。任何对象都可以成为一个模型。模型通常在控制器中使用JSON定义,或者从服务器中使用AJAX获取。模型可以是JSON对象,也可以只是一个字符串、数组,甚至一个数字。当然,您也可以将额外的函数添加到模型中,并将它们存储在JSON对象中,但这与Angular不太匹配。

在前端的模型并不是真正的模型。实际的模型,即真正的数据源,存储在服务器上。我们使用API进行同步,但如果两者之间存在冲突,数据库中的模型显然是最终的获胜者。这样可以保护诸如折扣代码等内容的隐私。您在前端找到的模型是实际模型的公共属性的同步版本。

业务逻辑可以存在于服务中。如果您想编写一个方法来对模型进行操作、同步或验证,您可以编写一个服务。服务是单例对象,与任何其他JavaScript对象一样,您可以在其中放置函数或数据。Angular提供了一组内置服务,如$http。您可以构建自己的服务,并使用依赖注入自动提供给控制器。服务可以包含与RESTful API交互的方法,或者验证数据的方法,或者您可能需要执行的任何其他工作。

当然,您不应该将服务用作模型。将其用作可以执行操作的对象。这是一种不同的思考方式,但是一种可行的方式。

总之,$scope是Angular中存储模型状态的地方。它通过原型继承与父$scope连接,形成一个树状结构,与DOM相对应。控制器用于初始化$scope对象,服务用于处理业务逻辑。前端模型只是服务器模型的同步版本。这种模型状态的管理方式使得在Angular中处理和组织数据变得更加简单和高效。

0