Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何使用AngularJS创建发布/订阅模式_Javascript_Angularjs_Publish Subscribe - Fatal编程技术网

Javascript 如何使用AngularJS创建发布/订阅模式

Javascript 如何使用AngularJS创建发布/订阅模式,javascript,angularjs,publish-subscribe,Javascript,Angularjs,Publish Subscribe,我正在使用angular(1.4.7)编写一个SPA,为了降低复杂性,我一直试图将持久性逻辑抽象到工厂/存储库中 这没什么特别的,看起来很好用 我想实现的一个特性是,当用户更新某些个人信息时,“父”作用域能够进行更新 参见示例 我已经研究了实现这一点的各种方法,我看到的一些方法是: 使用$rootScope共享公共对象我一直试图避免使用范围,而只使用controllerAs语法。这似乎是在控制器和视图之间保持严格/稳健分离的建议解决方案 使用$scope.$parent访问所需的属性出于类似原

我正在使用angular(1.4.7)编写一个SPA,为了降低复杂性,我一直试图将持久性逻辑抽象到工厂/存储库中

这没什么特别的,看起来很好用

我想实现的一个特性是,当用户更新某些个人信息时,“父”作用域能够进行更新

参见示例

我已经研究了实现这一点的各种方法,我看到的一些方法是:

  • 使用$rootScope共享公共对象
    我一直试图避免使用范围,而只使用
    controllerAs
    语法。这似乎是在控制器和视图之间保持严格/稳健分离的建议解决方案
  • 使用$scope.$parent访问所需的属性
    出于类似原因,这会将我的视图实现与我的控制器实现耦合起来
  • 使用$on/$emit在控制器之间通信
    这听起来像是一场最终的维护噩梦,但本质上意味着控制器知道其他控制器。不理想
我的理想场景是有一个酒吧/酒吧场景

我的用户更新他们的详细信息将由存储库处理,存储库将向该存储库的所有订阅者发送命令或履行承诺


这是标准的角度模式吗?如果不是,合适的替代方案是什么?

虽然它主要与React世界相关,但您正在寻找的是。它甚至被移植到角的形式

Flux为您如何看待流经应用程序的数据强制了一种模式

允许您使用发布和订阅更改的共享模型称为存储。然而,你不能用传统的方式和他们说话

商店 存储负责看管一些数据并处理您触发的任何操作。例如,计数器的存储可能如下所示:

app.store('CounterStore', function() {
  return {
    count: 0,
    increment: function() {
      this.count = this.count + 1;
      this.emitChange();
    },
    decrement: function() {
      this.count = this.count - 1;
      this.emitChange();
    },
    exports: {
      getCount: function() {
        return this.count;
      }
    }
  };
});
然后将存储注入控制器或指令以侦听更改

将其视为发布/订阅体系结构的订阅部分

app.directive('Counter', function() {
  return {
    template: '<div ng-bind='count'></div>',
    controller: function($scope, CounterStore) {
      $scope.listenTo(CounterStore, function() {
        $scope.count = CounterStore.getCount();
      });
    }
  };
});
在更传统的发布/订阅体系结构中,如果指令C想要与指令a和D通信,它必须维护一个复杂的纠缠层次结构,这在每次让一个指令或控制器知道另一个指令时变得越来越难以管理

目前还不清楚数据是以何种方式流动的,因为指令可以相互通信,而不管它们在哪里

  A <------------+
 / \             |
v   v            |
B   D  <----- [store]
|                ^
v                |
C --> [action] --+

A使用
$on/$emit
肯定是一个可行的选择,但您需要小心不要过度使用它,因为它可能会导致一个非常复杂的应用程序,很难调试和跟踪

另一种方法(我认为在大多数情况下更好)是使用服务。由于服务本质上是单例的,因此服务上的数据将在所有应用程序中共享

因此,您可以在父控制器和子控制器中插入一个服务,一旦对子控制器进行了更改,它将更新服务上的属性,父控制器将
$watch
该属性并根据更改采取行动:

var app = angular.module('myApp', []);

app.factory('sharedService', function() {
    return {
        sharedAttr: ''
    }

});    

app.controller('childCtrl', function($scope, sharedService) {
    $scope.onAttrChange = function() {
        sharedService.sharedAttr = 'Value Changed';
    }
});

app.controller('parentCtrl', function($scope, sharedService) {
    $scope.$watch(function() {
            return sharedService.sharedAttr;
        },
        function(newVal, oldVal) {
            //do something with newValue
        });
});    
我使用$bus并将其注入到$scopes中,如博客所示

请注意,blog中的代码片段抛出了一个无法获取未定义的属性“length”,我将其修复为:

app.config(function($provide) {
$provide.decorator('$rootScope', [
    '$delegate',
    function($delegate) {
        Object.defineProperty($delegate.constructor.prototype,
            '$bus', {
                get: function() {
                    var self = this;

                    return {
                        subscribe: function() {
                            var sub = postal.subscribe.apply(postal, arguments);

                            self.$on('$destroy',
                                function() {
                                    sub.unsubscribe();
                                });
                        },
                        //Fix to avoid postaljs v 2.0.4:513 Unable to get property 'length' of undefined
                        channel: function() { return postal.channel.apply(postal,arguments);  },
                        publish: function() { postal.publish.apply(postal,arguments); }
                    };
                },
                enumerable: false
            });

        return $delegate;
    }
]);
订阅控制器:

var subscription = $scope.$bus.subscribe({
            channel: "organizations",
            topic: "item.changed",
            callback: function(data, envelope) {
                // `data` is the data published by the publisher.
                // `envelope` is a wrapper around the data & contains
                // metadata about the message like the channel, topic,
                // timestamp and any other data which might have been
                // added by the sender.
            }
        });
channel = $scope.$bus.channel('organizations');
channel.publish("item.changed",data);
发布控制器:

var subscription = $scope.$bus.subscribe({
            channel: "organizations",
            topic: "item.changed",
            callback: function(data, envelope) {
                // `data` is the data published by the publisher.
                // `envelope` is a wrapper around the data & contains
                // metadata about the message like the channel, topic,
                // timestamp and any other data which might have been
                // added by the sender.
            }
        });
channel = $scope.$bus.channel('organizations');
channel.publish("item.changed",data);

丹骑着他的骏马进来了!这正是我想要做的。我来自一个微服务的世界,一想到要编写长时间的高度耦合的类,我就觉得自己是一只悲伤的熊猫。非常感谢您的帮助。别忘了看看RxJs的使用,这是Angular 2的发展方向。我更喜欢这种方式来改变我自己,尽管它们不是相互排斥的,因为它可以让你更好地控制数据流如何通过你的应用程序。这实际上非常有趣!我以前在各种应用程序中使用过Rx,所以这是一个我熟悉的概念。如果你有时间,你会考虑贡献一个RXJS的例子吗?我忘了提到这是我调查过的东西。这不一定是一个糟糕的体系结构,我认为它有它的位置,但理想情况下,我正在寻找能够在大型应用程序中扩展的东西。这是对我问题的正确回答,所以你得到+1:)