管理Controller层次结构之间的数据流

时间:2014-08-27 22:01:28

标签: angularjs

我的应用程序的一部分在3个单独的页面之间共享信息。我有一个摘要"订单"实例化其子节点时实例化的控制器。孩子们是"概述","警报"和"帐户"。所以我的视图/控制器层次结构看起来像

                                   Order
                                   / |  \
                                  /  |   \
                                 /   |    \
                                /    |     \
                               /     |      \
                          Overview  Alerts  Accounts

在这3个页面的顶部,我显示了一些"订单"等级信息,如客户名称,因此我在"订单"中进行API调用。控制器,以便它可以在任何页面上使用。问题是我想保持我的所有API数据都包含在"模型中的约定"像$scope.model这样的对象。我尝试在我的"概述"中使用angular.extend。控制器使用" Order"中存在的$scope.model来扩展此控制器的$scope.model。控制器,问题是angular.extend在返回API调用之前执行,所以我基本上只是扩展一个从未实际填充API数据的空白对象。

我的解决方案是使用Angular Events从Parent触发到Child,以便在API调用完成后扩展对象。我的代码如下所示:

订单控制器

$scope.model = new OrderModel();

    API.Backups.getBackupService({ id: $stateParams.orderId }, function (data) {
        $scope.model.BackupService.data = data.result;
        $scope.$broadcast('parentDataReceived', $scope.model.BackupService.data);
    });

概述控制器

$scope.model = new OverviewModel();

    $scope.$on('parentDataReceived', function (event, data) {
        angular.extend($scope.model.BackupService.data, data);
    });

这很好用,但我不认为这是最好的解决方案。以前是以更优雅的方式解决了这个问题还是我的方式还好?


那么更正确的解决方案是

app.factory('OrderService', function() {
  var OrderService = {};
  var order = {};

  OrderService.getOrder = function(id) { //send API call to get order information via OrderID }
  OrderService.updateOrder = function(order) { //send API to PUT the new order information to the server }
  OrderService.Current = order;

  return OrderService;
});

1 个答案:

答案 0 :(得分:0)

你正在以错误的方式解决问题。您不需要从控制器进行REST调用,然后在接收数据时将数据推送到模型(有效地将数据从控制器推送到服务)。

而是通过控制器的$ scope将您的视图绑定到服务的数据,并让数据从服务流经您的控制器的$ scope并进入您的视图。

为此,请创建订单服务,然后将Controller的$ scope(例如$ scope.model.order)上的属性分配给此Orders服务的currentOrder属性。然后,当收到数据时,只需将其分配给Orders服务中的currentOrder属性即可。

因为您的Controller的$ scope.model.order属性引用(即'绑定到')与Orders.currentOrder相同的对象,$ scope.model.order也将立即更新,视图(即HTML)

所以在你的例子中,你有类似的东西:

控制器

angular.module('OrderApp', [])
.controller('OrderCtrl', ['$scope', 'Orders', function($scope, Orders){

    // $scope.model glues the values in your actual model (Orders service) to the
    // view defined in your HTML template.
    $scope.model = {};

    // Assign $scope.model.order to OrderService.currentOrder. Because 
    // $scope.model.order and Orders.currentOrder both reference the same 
    // object, whenever Orders.currentOrder changes, $scope.model.order 
    // will change as well.  
    //
    // Note that in your view, {{model.order}} will also automatically
    // update.
    $scope.model.order = OrderService.getCurrentOrder();

    // Assume in your view you have a button wired up to getOrder() 
    // (e.g. ng-click=getOrder() ). Then you can display a message 
    // depending on whether the data has been successfully retrieved 
    // or not, like so:
    $scope.getOrder() = function(){

        // Call Orders' getOrder(). This will populate 
        // Orders.currentOrder; the change in currentOrder will
        // instantly be reflected in $scope.model.order as they both 
        // reference the same object, so you don't need to worry about 
        // reassigning $scope.model.order to the new object referenced 
        // by Orders.currentOrder.
        Orders.getOrder().then(function(){
            $scope.infoMsg = "Order received ok";
        },
        function(){
            $scope.errorMsg = "Error receiving order";
        });

})

订购服务

// OrderService acts as your model
.factory('OrderService', ['API', function(API){

    var currentOrder = {};

    // These are the public functions that your Controller 
    // (and other services) can use
    var service = {
        getOrder: getOrder,
        getCurrentOrder: getCurrentOrder,
        updateOrder: updateOrder
    }

    return service;

    /////////////

    function getOrder(){
        // Return $http's promise to your Controller
        return API.getBackupServiceData().then(function(data){
            // When the data is retrieved, currentOrder is populated.
            // The change in currentOrder will automatically be 
            // reflected in your Controller's $scope.model.order as 
            // they both reference the same object
            currentOrder = data;
        });
    }

    function getCurrentOrder(){
        return currentOrder;
    }
})

单独的API服务

.factory('API', ['$http', function($http){

    var service = {
        getBackupServiceData: getBackupServiceData;
    };

    return service;

    ////////////

    function getBackupServiceData(){
        // Return $http's promise
        return $http.get({ id: $stateParams.orderId }, function (data) {
            // transform data if needed
            return data;
        },
        function(response){
            // handle error
        }
    });

}])

请注意,您经常会读到控制器应该是“粘合剂”'在你的模型和视图之间,但在Angular-land中它的含义并不总是很明显。

简单地说,您的控制器应该只包含$ scope的赋值。如果控制器中有一个包含业务逻辑的函数,或者对最终分配给$ scope的数据执行或转换的函数,请将该函数放入服务中。