AngularJS触发并监视来自另一个模块的控制器的服务对象值(扩展)

时间:2015-07-13 11:13:27

标签: javascript html angularjs

参考这个问题 AngularJS trigger and watch object value change in service from controller

它正在尝试从控制器中查看服务的更改。 我试图扩展它以处理多个模块(在同一页面的不同div中的并发应用程序)通信。

问题:

我想实现类似的壮举,但情节略有不同。我有两个模块myApp和yourApp。 myApp有一项服务。我想在您的App模块的控制器中观察myApp服务的变化。可以吗?或者是否有不同的方法来反映和检测另一个模块内一个模块的数据变化。

考虑以下示例代码:

HTML

<div ng-app="myApp">
    <div ng-controller="MyCtrl">
        <div ng-click="setFTag()">Click Me</div>
    </div>
</div>
<div ng-app="yourApp">
    <div ng-controller="yourCtrl">       
    </div>
</div>

的Javascript

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

// myApp's service
myApp.service('myService', function() {
    this.tags = {
        a: true,
        b: true
    };

    this.setFalseTag = function() {
        alert("Within myService->setFalseTag");
        this.tags.a = false;
        this.tags.b = false;

    //how do I get the watch in YourCtrl of yourApp module to be triggered?
    };
});

// myApp's controller
myApp.controller('MyCtrl', function($scope, myService) {

    //$scope.myService = myService;    
    $scope.setFTag = function() {
        alert("Within MyCtrl->setFTag");
        myService.setFalseTag();
    };        

    /*
    $scope.$watch(function () {
        return myService.tags;
    }, function(newVal, oldVal) {
        alert("Inside watch");
        console.log(newVal);
        console.log(oldVal);
    }, true);  
    */
});

// yourApp module (Injecting myApp module into yourApp module)
var yourApp = angular.module('yourApp',['myApp']);
// yourApp's controller
yourApp.controller('YourCtrl', function($scope, myService) {

    $scope.$watch(function () {
        return myService.tags;
    }, function(newVal, oldVal) {
        alert("Inside watch of yourcontroller");
        console.log(newVal);
        console.log(oldVal);
    }, true);

});

注意:我不确定这是否是在模块之间进行通信的正确方法。任何建议或解决方案都将受到高度赞赏。

P.S。我已经引导了两个模块以适应同一页面。

JSFiddle

1 个答案:

答案 0 :(得分:1)

模块之间的通信与应用程序之间的通信完全不同。

模块之间进行通信的情况下,只需将模块A注入模块B即可。

在这种情况下,模块B可以完全访问模块A中公开的任何注入/通信。

然而,应用之间的通信稍微复杂一些。你需要在外面设置一些东西&#39;角度世界,从两个应用程序接受属性。

我已经整理了一个jsBin,展示了你可以做到的

话虽如此,我不确定我是否会推荐它 - 但是那时候关于这个问题的最佳实践再也不存在了。

它的要点是;

  1. 设置外部 Angular世界的共享服务的新实例
  2. 将所述服务的实例附加到window
  3. 通过$window在您的应用特定服务/控制器中访问上述实例。
  4. 注册需要访问共享服务中存储的数据的每个 $范围。
  5. 在更新共享服务中的数据后,循环注册的$ scopes并触发$evalAsync(以便最终不会以$digest already in progress结束)。
  6. 观察您的数据是否跨应用程序同步。
  7. 这只是一个关于如何做的PoC,我不推荐它,因为它在单元测试方面有点像打击。还因为我们在window上公开了属性。 yuck。

    当然,您可以忽略window上的曝光 - 但是您的代码必须存在于同一个文件中( afaic )。还有一个, yuck。

    在此基础上,如果你决定(或者,能够)只使用一个app(多个模块就好了)并想要与多个组件通信/同步服务,我认为这个这将是最好的方式:

    app.service('shared', function () {
      var data = {
          a: true,
          b: true
      };
    
      this.toggle = function() {
        data.a = !data.a;
        data.b = !data.b;
      };
    
      Object.defineProperty(this, 'data', {
          get: function () {
              return data;
          }
      });      
    });
    

    通过使用对象getter,您不需要设置$watch来在同一模块中的组件之间同步数据。也不会触发手册$digest

    another jsbin - 展示上述内容。

    我看到两个模块两个应用之间的区别:

    2个模块

    两个独立的模块,捆绑在一起&#39;一起进入一个应用程序(通过第三个模块,或将模块A注入B)。

    var app1 = angular.module('app1', ['app2', 'app3']);
    
    var app2 = angular.module('app2', []);
    
    var app3 = angular.module('app3', []);
    
    angular.bootstrap(/*domElement*/, app1);
    

    2个应用

    var app1 = angular.module('app1', []);
    var app2 = angular.module('app2', []);
    
    angular.bootstrap(/*domElement1*/, app1);
    angular.bootstrap(/*domElement2*/, app2);
    

    我认为在拥有两个应用程序并在两者之间共享state时, 我认为运行两个应用程序的重点是将两者分开。否则它只是工程 imho

    一些想法:

    • 您可以为这两个应用程序添加一个公共依赖项。它可能不是共享状态,但您可以在两个应用程序中访问相同的实现。
    • 您可以可能利用sessionStorage作为两种应用程序之间数据的传输媒介。确保事后清理:)