在哪里放置模型数据和行为?[TL; 博士; 使用服务]

Nil*_*ste 340 javascript model-view-controller dci angularjs

我正在与AngularJS合作完成我的最新项目.在文档和教程中,所有模型数据都放入控制器范围.我知道必须存在控制器,因此在相应的视图中.

但是,我不认为该模型应该在那里实施.它可能很复杂并且具有私有属性.此外,人们可能希望在另一个上下文/应用程序中重用它.将所有内容放入控制器完全打破了MVC模式.

对于任何模型的行为都是如此.如果我使用DCI架构并从数据模型中分离行为,我将不得不引入其他对象来保存行为.这可以通过引入角色和上下文来完成.

当然,模型数据和行为可以使用普通的javascript对象或任何"类"模式来实现.但AngularJS的做法是什么呢?使用服务?

所以它归结为这个问题:

在AngularJS最佳实践之后,您如何实现与控制器分离的模型?

And*_*lin 154

如果您想要多个控制器可以使用的东西,您应该使用服务.这是一个简单的人为例子:

myApp.factory('ListService', function() {
  var ListService = {};
  var list = [];
  ListService.getItem = function(index) { return list[index]; }
  ListService.addItem = function(item) { list.push(item); }
  ListService.removeItem = function(item) { list.splice(list.indexOf(item), 1) }
  ListService.size = function() { return list.length; }

  return ListService;
});

function Ctrl1($scope, ListService) {
  //Can add/remove/get items from shared list
}

function Ctrl2($scope, ListService) {
  //Can add/remove/get items from shared list
}
Run Code Online (Sandbox Code Playgroud)

  • 使用服务而不仅仅是创建一个简单的Javascript对象作为模型并将其分配给控制器范围会有什么好处? (23认同)
  • 如果您需要在多个控制器之间共享相同的逻辑.而且,这种方式更容易独立测试. (22认同)
  • 是的,使用普通的旧Javascript对象,您将无法将任何Angular注入ListService.就像在这个例子中一样,如果你需要$ http.get来在开始时检索List数据,或者你需要注入$ rootScope以便你可以$ broadcast事件. (9认同)

Ben*_*n G 80

目前,我想要这种模式,这虽然不是DCI,提供了一个经典的服务/模型去耦(与服务谈话Web服务(又名模型CRUD)和模型定义对象的属性和方法).

请注意,每当模型对象需要处理其自身属性的方法时,我才会使用此模式,我可能会在任何地方使用它(例如改进的getter/setter).我不是主张系统地为每项服务做这件事.

编辑:我曾经认为这种模式会违背"Angular模型是普通的旧javascript对象"的口头禅,但现在我觉得这种模式非常好.

编辑(2):为了更清楚,我只使用Model类来计算简单的getter/setter(例如:在视图模板中使用).对于大型业务逻辑,我建议使用"了解"模型的单独服务,但要与它们分开,并且只包含业务逻辑.如果需要,可将其称为"业务专家"服务层

service/ElementServices.js(注意如何在声明中注入Element)

MyApp.service('ElementServices', function($http, $q, Element)
{
    this.getById = function(id)
    {
        return $http.get('/element/' + id).then(
            function(response)
            {
                //this is where the Element model is used
                return new Element(response.data);
            },
            function(response)
            {
                return $q.reject(response.data.error);
            }
        );
    };
    ... other CRUD methods
}
Run Code Online (Sandbox Code Playgroud)

model/Element.js(使用angularjs Factory,用于创建对象)

MyApp.factory('Element', function()
{
    var Element = function(data) {
        //set defaults properties and functions
        angular.extend(this, {
            id:null,
            collection1:[],
            collection2:[],
            status:'NEW',
            //... other properties

            //dummy isNew function that would work on two properties to harden code
            isNew:function(){
                return (this.status=='NEW' || this.id == null);
            }
        });
        angular.extend(this, data);
    };
    return Element;
});
Run Code Online (Sandbox Code Playgroud)

  • 我刚刚进入Angular,但我很想知道退伍军人是否/为什么认为这是异端邪说.这可能是我最初接近它的方式.有人可以提供一些反馈吗? (4认同)
  • 对我来说这看起来并不像是一种异端,你正在使用工厂来创建它们:构建对象.我相信"angularjs不需要模型"这个短语意味着"你不需要继承特殊的类,或者使用特殊的方法(比如ko.observable,在淘汰赛中)"以便使用角度模型,纯粹的js对象就足够了". (3认同)
  • @Aaronius只是要明确:我从来没有在任何angularjs doc或博客上读过"你永远不应该这样做",但我总是读过像"angularjs不需要模型,它只是使用普通的旧javascript"之类的东西,我必须自己发现这种模式.由于这是我在AngularJS上的第一个真正的项目,我正在发出那些强烈警告,以便人们不先思考就不会复制/粘贴. (2认同)

S.C*_*.C. 29

Angularjs文件明确指出:

与许多其他框架不同,Angular对模型没有任何限制或要求.没有要继承的类或用于访问或更改模型的特殊访问器方法.模型可以是原始,对象哈希或完整对象类型.简而言之,该模型是一个普通的JavaScript对象.

因此,这意味着由您决定如何声明模型.这是一个简单的Javascript对象.

我个人不会使用Angular Services,因为它们的行为类似于您可以使用的单例对象,例如,在您的应用程序中保持全局状态.

  • 它出现在旧的angularjs文档中(回答时还活着):https://github.com/gitsome/docular/blob/master/lib/angular/ngdocs/guide/concepts.ngdoc (4认同)

Run*_* FS 8

DCI是一种范例,因此没有angularJS方法,无论是语言支持DCI还是不支持DCI.如果你愿意使用源代码转换,JS会很好地支持DCI,如果你不愿意,则会有一些缺点.DCI再次与依赖注入无关,而不是说C#类具有并且绝对不是服务.因此,使用angulusJS进行DCI的最佳方法是使用JS方式进行DCI,这与DCI首先制定的方式非常接近.除非您进行源转换,否则您将无法完全执行此操作,因为即使在上下文之外,角色方法也将成为对象的一部分,但这通常是基于方法注入的DCI的问题.如果你看看DCI的权威网站fullOO.info你可以看一下他们也使用方法注入的ruby实现,或者你可以看看这里有关DCI的更多信息.它主要是使用RUby示例,但DCI的内容与此无关.DCI的关键之一是系统所做的与系统分离.因此,数据对象非常愚蠢,但一旦绑定到上下文角色中的角色,方法就会使某些行为可用.角色只是一个标识符,仅此而已,当通过该标识符访问对象时,角色方法可用.没有角色对象/类.使用方法注入时,角色方法的范围并不完全如描述但接近.JS中的上下文的一个例子可以是

function transfer(source,destination){
   source.transfer = function(amount){
        source.withdraw(amount);
        source.log("withdrew " + amount);
        destination.receive(amount);
   };
   destination.receive = function(amount){
      destination.deposit(amount);
      destination.log("deposited " + amount);
   };
   this.transfer = function(amount){
    source.transfer(amount);
   };
}
Run Code Online (Sandbox Code Playgroud)


mar*_*oda 7

这篇关于AngularJS中的模型的文章可能会有所帮助:

http://joelhooks.com/blog/2013/04/24/modeling-data-and-state-in-your-angularjs-application/

  • 请注意,不鼓励[仅链接答案](http://meta.stackoverflow.com/tags/link-only-answers/info),SO答案应该是搜索解决方案的终点(相比之下)引用的另一个中途停留,随着时间的推移往往会变得陈旧.请考虑在此处添加独立的概要,并将链接作为参考. (7认同)

小智 5

正如其他海报所述,Angular没有为建模提供开箱即用的基类,但可以有用地提供几个功能:

  1. 与RESTful API交互和创建新对象的方法
  2. 建立模型之间的关系
  3. 在持久化到后端之前验证数据; 也可用于显示实时错误
  4. 缓存和延迟加载,以防止浪费HTTP请求
  5. 状态机挂钩(保存,更新,创建,新建等之前/之后)

一个完成所有这些工作的库是ngActiveResource(https://github.com/FacultyCreative/ngActiveResource).完全披露 - 我写了这个库 - 我已成功地用它来构建几个企业级应用程序.它经过了充分测试,并提供了Rails开发人员应该熟悉的API.

我和我的团队继续积极开发这个库,我很想看到更多Angular开发人员为此做出贡献并对其进行测试.


TGH*_*TGH 5

一个较老的问题,但我认为鉴于Angular 2.0的新方向,该主题比以往任何时候都更具相关性.我想说最好的做法是编写尽可能少的依赖于特定框架的代码.仅使用特定于框架的部分来增加直接价值.

目前似乎Angular服务是为少数几个概念提供给下一代Angular的概念之一,因此遵循将所有逻辑转移到服务的一般准则可能是明智的.但是,我认为即使没有直接依赖Angular服务,也可以制作解耦模型.创建只包含必要依赖关系和责任的自包含对象可能是最佳选择.它还可以在进行自动化测试时使生活更轻松.如今,单一责任是一项嗡嗡声的工作,但它确实很有意义!

这是一个我认为适合将对象模型与dom分离的模式示例.

http://www.syntaxsuccess.com/viewarticle/548ebac8ecdac75c8a09d58e

一个关键的目标是以一种方式构建代码,使其从单元测试和视图一样容易使用.如果您实现了这一目标,那么您就可以编写实际且有用的测试.