AngularJS:如何使用丰富的分层对象模型构建控制器和工厂/服务?

ric*_*ard 30 structure object-model angularjs angularjs-factory angularjs-provider

我读了这两篇很棒的文章:

Jonathan Creamer 的angularjs控制器状态

由Todd Motto 重新思考AngularJS控制器

在这些文章中,作者讨论了使用控制器的正确方法(使它们成为视图和模型之间的贫血桥梁)和工厂/服务(业务逻辑应该存在的地方).

这是很好的信息,我很高兴开始在我的一个项目上重构控制器,但我很快发现,如果你有一个丰富的对象模型,文章中显示的结构就会崩溃.

以下是"重新思考Angularjs控制器"的设置概述:

这是控制器:

app.controller('InboxCtrl', function InboxCtrl (InboxFactory) {

    var vm = this;

    vm.messages = InboxFactory.messages;

    vm.openMessage = function (message) {
      InboxFactory.openMessage(message);
    };

    vm.deleteMessage = function (message) {
      InboxFactory.deleteMessage(message);
    };

    InboxFactory
      .getMessages()
      .then(function () {
      vm.messages = InboxFactory.messages;
    });

});
Run Code Online (Sandbox Code Playgroud)

这是工厂:

app.factory('InboxFactory', function InboxFactory ($location, NotificationFactory) {

  factory.messages = [];

  factory.openMessage = function (message) {
    $location.search('id', message.id).path('/message');
  };

  factory.deleteMessage = function (message) {
    $http.post('/message/delete', message)
    .success(function (data) {
      factory.messages.splice(index, 1);
      NotificationFactory.showSuccess();
    })
    .error(function () {
      NotificationFactory.showError();
    });
  };

  factory.getMessages = function () {
    return $http.get('/messages')
    .success(function (data) {
      factory.messages = data;
    })
    .error(function () {
      NotificationFactory.showError();
    });
  };

  return factory;

});
Run Code Online (Sandbox Code Playgroud)

这很棒,因为providers(工厂)是单例,数据在视图之间保持,无需从API重新加载即可访问.

如果messages是顶级对象,这可以正常工作.但如果他们不是,会发生什么?如果这是用于浏览其他用户的收件箱的应用程序怎么办?也许您是管理员,并希望能够管理和浏览任何用户的收件箱.也许您需要同时加载多个用户的收件箱.这是如何运作的?问题是收件箱消息存储在服务中,即InboxFactory.messages.

如果层次结构如下所示:

                           Organization
                                |
              __________________|____________________
             |                  |                    |
         Accounting       Human Resources            IT
             |                  |                    |
     ________|_______      _____|______        ______|________
    |        |       |    |     |      |      |      |        |
   John     Mike    Sue  Tom   Joe    Brad   May    Judy     Jill
    |        |       |    |     |       |     |      |        |
   Inbox    Inbox  Inbox Inbox Inbox  Inbox Inbox  Inbox    Inbox
Run Code Online (Sandbox Code Playgroud)

现在messages是层次结构中的几个层次,并且没有任何意义.您无法在工厂中存储消息,InboxFactory.messages因为您必须一次为多个用户检索消息.

现在您将拥有一个OrganizationFactory,一个DepartmentFactory,一个UserFactory和一个InboxFactory.检索"消息"必须位于a的上下文中user,该上下文位于a department的上下文中organization.数据的存储方式和位置?如何进行检索?

那怎么解决呢?如何构建控制器,工厂/服务和丰富的对象模型?

在我的思考中,我倾向于保持精益,而不是拥有丰富的对象模型.只需将对象存储在注入控制器的$ scope中,如果导航到新视图,请从API重新加载.如果您需要跨视图保留一些数据,您可以使用服务或工厂构建该桥,但它不应该是您执行大多数操作的方式.

其他人如何解决这个问题?这有什么模式吗?

ric*_*ard 0

经过大量修改和尝试不同的方法之后,我的最终决定是您不应该跨视图保留丰富的对象模型。

我保持对象模型超级精简,并加载每个视图所需的内容。我保留了高级数据(用户信息,如姓名、ID、电子邮件等,以及组织数据,如他们登录的组织),但其他所有内容都会加载到当前视图中。

采用这种精益方法,我的工厂将如下所示:

app.factory('InboxFactory', function InboxFactory ($location, NotificationFactory) {

factory.messages = [];

factory.openMessage = function (message) {
  $location.search('id', message.id).path('/message');
};

factory.deleteMessage = function (message) {
  $http.post('/message/delete', message)
  .success(function (data) {
    NotificationFactory.showSuccess();
    return data;
  })
  .error(function () {
    NotificationFactory.showError();
    return null;
  });
};

factory.getMessages = function (userId) {
  return $http.get('/messages/user/id/'+userId)
  .success(function (data) {
    return data;
  })
  .error(function () {
    NotificationFactory.showError();
    return null;
  });
};

return factory;

});
Run Code Online (Sandbox Code Playgroud)

和控制器:

app.controller('InboxCtrl', function InboxCtrl (InboxFactory) {

  var vm = this;

  vm.messages = {};

  vm.openMessage = function (message) {
    InboxFactory.openMessage(message);
  };

  vm.deleteMessage = function (message) {
    InboxFactory.deleteMessage(message);
  };

  InboxFactory
    .getMessages(userId) //you can get the userId from anywhere you want.
    .then(function (data) {
      vm.messages = data;
  });

});
Run Code Online (Sandbox Code Playgroud)

到目前为止的好处是:

  • 简化的应用逻辑
  • 精简、简单、轻量级(我只加载当前状态所需的内容)
  • 更少的内存使用,这意味着整体性能更好,尤其是在移动设备上