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;
    });
});
这是工厂:
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;
});
这很棒,因为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
现在messages是层次结构中的几个层次,并且没有任何意义.您无法在工厂中存储消息,InboxFactory.messages因为您必须一次为多个用户检索消息.
现在您将拥有一个OrganizationFactory,一个DepartmentFactory,一个UserFactory和一个InboxFactory.检索"消息"必须位于a的上下文中user,该上下文位于a department的上下文中organization.数据的存储方式和位置?如何进行检索?
那怎么解决呢?如何构建控制器,工厂/服务和丰富的对象模型?
在我的思考中,我倾向于保持精益,而不是拥有丰富的对象模型.只需将对象存储在注入控制器的$ scope中,如果导航到新视图,请从API重新加载.如果您需要跨视图保留一些数据,您可以使用服务或工厂构建该桥,但它不应该是您执行大多数操作的方式.
其他人如何解决这个问题?这有什么模式吗?
经过大量修改和尝试不同的方法之后,我的最终决定是您不应该跨视图保留丰富的对象模型。
我保持对象模型超级精简,并加载每个视图所需的内容。我保留了高级数据(用户信息,如姓名、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;
});
和控制器:
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;
  });
});
到目前为止的好处是: