AngularJS绑定变量在范围之外并通知更新?

时间:2014-12-28 06:05:55

标签: javascript angularjs

我是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值更改时一样,通知相关属性应用最新值?

谢谢

3 个答案:

答案 0 :(得分:4)

你错了,因为你不明白

  • 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
    }
})

答案 1 :(得分: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;
});

答案 2 :(得分:1)

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不知道它。因此,它不会进行消化循环。