【问题标题】:AngularJS binding variable outside of scope and notify update?AngularJS绑定变量超出范围并通知更新?
【发布时间】:2014-12-28 14:57:10
【问题描述】:

我是 AngularJS 的新手。这是我的问题。

我有一个像 var isStateA = false 这样的页面级变量。我已将此变量分配给我的控制器变量,如下所示:

var isStateA = false;

app.controller('AController',function($scope){
    $scope.shouldShow = isStateA;
});

app.controller('BController',function($scope){
    $scope.shouldShow = !isStateA;
});

shouldShow 属性相应地绑定到ng-show

预期的行为是当我将 isStateA 更改为 true 时。两个控制器范围内的值应该改变,因此它们应该执行显示/隐藏逻辑。

但是我上面的代码并没有发生这种情况。我想知道是否有办法做到这一点?比如isStateA值发生变化时,通知相关属性应用最新值?

谢谢

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    你搞错了,因为你不明白

    • AngularJS 观察者
    • javascript 通过引用传递

    AngularJS 知道由于观察者,应用程序中的值发生了变化。观察者在很多地方分配,但在您的情况下,当您在模板中使用 $scope.shouldShow 时。更改 $scope.shouldShow 的值将被 angular 和 work 拾取,但更改 isStateA 不会,这是因为它们不是同一个变量。这是正确的解决方案:

    // Your code
    app.service('stateAService', function() {
        this.isStateA = false;
    })
    app.controller('AController', function($scope, stateAService) {
        $scope.stateAService = stateAService;
    })
    app.controller('BController', function($scope, stateAService) {
        $scope.stateAService = stateAService;
    })
    
    // Template, controller A
    <div ng-show="stateAService.isStateA">
    </div>
    
    // Template, controller B
    <div ng-show="!stateAService.isStateA"></div>
    
    // Some code, anywhere else in your app
    app.controller('WhateverController', function($scope, stateAService) {
        this.hideBAndShowA = function() {
            stateAService.isStateA = true;
            // The change to stateAService gets picked up by the watchers, all good
        }
    })
    

    【讨论】:

      【解决方案2】:

      Angular 没有 $watch isStateA 变量,因此第二个更改不会被 Angular “拾取”。

      当你分配时:

      $scope.shouldShow = isStateA;
      

      您所做的只是将一个原始布尔值(按值)分配给范围变量。

      你的做法是一个不好的做法,但如果你坚持......

      要解决这个问题,您可以将$scope.shouldShow 设为函数:

      app.controller('AController',function($scope){
          $scope.shouldShow = function(){ return isStateA; };
      });
      
      app.controller('BController',function($scope){
          $scope.shouldShow = function(){ return !isStateA; };
      });
      

      或者一个对象(由@aj_r 建议)。

      不过,这还是行不通,因为您需要让 Angular 知道发生了变化。这是 BAD PRACTICE 部分(取自SO answer):

      // assuming <body> is the root element of your Angular app
      var $body = angular.element(document.body); 
      var $rootScope = $body.scope().$root;        
      $rootScope.$apply(function () {               
         isStateA = !isStateA;
      });
      

      【讨论】:

        【解决方案3】:

        isStateA 按值传递到$scope.shouldShow,这意味着该值被复制,并且没有创建引用。

        有一个简单的解决方案,但我推荐它,因为它不遵循 AngularJS 的正确模式。如果您愿意,请跳到此答案的末尾。

        您实际上应该只从控制器内部更新$scope 变量(或者如果您必须进行DOM 交互,则需要一个指令)。我不确定你想用这个做什么,但应该有一种方法来构建你的代码,这样你就可以摆脱isStateA,并直接在你的控制器中设置$scope.shouldShow = true。为什么需要在 2 个不同的控制器中访问相同的范围变量?也许您应该将它们组合成一个通用控制器,或者创建一个可以注入两个控制器的服务/工厂。

        简单(但不推荐)的解决方案是使用对象创建引用:

        var isStateA = { shouldShow: false };
        
        app.controller('AController',function($scope){
            $scope.state = isStateA;
        });
        // Now whenever you set isStateA.shouldShow, it should update the model and the view.
        

        注意:如果您在控制器之外设置isStateA .shouldShow,那么您的视图将不会更新,因为 Angular 不会知道它。因此,它不会运行摘要循环。

        【讨论】:

        • 知道为什么第二个按钮不起作用而第一个按钮起作用吗?看起来这就是 Angular 监控 $scope 变化的方式。你将如何让它发挥作用? plnkr.co/edit/SbzhkiCOtevIaXFm29lC?p=preview
        • 这只会在它第一次运行时起作用。 Angular 之外对 shouldShow 的更改不会被“拾取”,因为它们发生在 Angular 的摘要周期之外(即 Angular 不会知道更改已经发生)。
        • 根据你的 plnkr,你的控制器可以很容易地组合成一个控制器,这消除了所有这些的需要,尽管我认为你的情况比你的 plnkr 更复杂。不过,看看我的叉子,看看我的意思:plnkr.co/edit/RWsn3lKZrwuWb5F9ZRb0?p=preview
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-07
        • 1970-01-01
        • 2017-11-10
        • 2013-05-31
        • 2016-04-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多