【问题标题】:Isolated scope not updated隔离范围未更新
【发布时间】:2014-12-01 21:36:17
【问题描述】:

我有以下代码:

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

testApp.directive('myDirective', function () {
    return {
        scope: {
            child: '=child'
        },
        
        controller: function ($scope, $element, $attrs) {
            $scope.$on('childChanged', function (event, newChild) {
                if ($scope.child.id != newChild.id) {
                    alert("The child in the isolated scope is not updated!");
                }
                else {
                    alert("success");                    
                }
            });
        }
    };
});

testApp.controller('myController', function ($scope) {
    $scope.parentObject = {childObject: {id:1}};
    $scope.changeChild = function changeChild()
    {
        var newChild = { id: $scope.parentObject.childObject.id + 1};
        $scope.parentObject.childObject = newChild;
        //$scope.$apply(); //This solves the problem
        $scope.$broadcast('childChanged', newChild);
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-app="testApp">
    <div data-ng-controller="myController">        
        <div my-directive child="parentObject.childObject"></div>
        <button data-ng-click="changeChild()">Change Child</button>
    </div>
</div>

解释:

  • 我正在为指令创建一个隔离范围,具有双向 绑定到父范围的对象 (parentObject.childObject)。
  • 当点击按钮时,函数 changeChild 被调用 我的控制器。该功能将取代 $scope.parentObject.childObject 与另一个孩子,并将 广播活动。
  • 此事件的侦听器位于指令的控制器中。在里面 侦听器,我们检查孤立范围($scope.child)中的孩子是否是 与事件中发送的相同(即父母的 scope.parentObject.childObject)。 我们看到他们不一样,这意味着我们收到的孩子 隔离范围尚未更新。

请注意,如果我在广播之前使用 $scope.$apply(),那么指令控制器中的 $scope.child 将被更新,但是,它会抛出以下异常:“$apply already in progress”。

有人可以帮我理解这里发生了什么吗?为什么 $scope.$apply 有帮助,即使它只抛出了一个异常?如何在不调用 $scope.$apply 的情况下解决这个问题? 我想知道是否有一种方法可以确保隔离范围中的绑定属性在父范围中发生更改后得到更新,而无需在事件中传递它。

谢谢

【问题讨论】:

    标签: javascript angularjs scope directive


    【解决方案1】:

    您可以在更新 child.id 后使用 $timeout 调用下一个摘要周期

    请看下面的演示

    var testApp = angular.module('testApp', []);
    
    testApp.directive('myDirective', function() {
      return {
        scope: {
          child: '=child'
        },
    
        controller: function($scope, $element, $attrs) {
          $scope.$on('childChanged', function(event, newChild) {
    
            if ($scope.child.id != newChild.id) {
              alert("The child in the isolated scope is not updated?");
            } else {
              alert("success");
            }
          });
    
        }
      };
    });
    
    testApp.controller('myController', function($scope, $timeout) {
      $scope.parentObject = {
        childObject: {
          id: 1
        }
      };
      $scope.changeChild = function changeChild() {
        var newChild = {
          id: $scope.parentObject.childObject.id + 1
        };
        $scope.parentObject.childObject = newChild;
    
        $timeout(function() {
          $scope.$broadcast('childChanged', newChild);
        }, 0);
      }
    });
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <div data-ng-app="testApp">
      <div data-ng-controller="myController">
        <div my-directive child="parentObject.childObject"></div>
        <button data-ng-click="changeChild()">Change Child {{parentObject.childObject}}</button>
      </div>
    </div>

    【讨论】:

    • 谢谢,这确实解决了问题。我是 js 和 AngularJs 的新手,你能解释一下为什么这个解决方案有效吗?这是此类情况的最佳做法吗? (抱歉我不能投票,我也是stackoverflow新手...)
    • @user2051749 在您的示例中,当您广播 newChild angularjs 处于摘要循环期间并且 newChild 未更新时,您需要调用另一个摘要周期来广播新值 (stackoverflow.com/questions/16066239/…)。我宁愿在你的指令中使用 $watch 而不是 $broadcast 请看这里jsbin.com/nibopa/1/edit
    • 感谢您的解释。我在提交问题之前尝试使用 $watch,但我在 newValue 和 oldValue 中都收到了“未定义”。不知道为什么,因为您的示例(jsbin.com/nibopa/1/edit)运行良好,并且代码似乎与我的相同...... :(在我看到以下帖子后,我尝试使用 $broadcast 代替:@ 987654323@
    猜你喜欢
    • 1970-01-01
    • 2014-04-28
    • 1970-01-01
    • 2015-12-01
    • 1970-01-01
    • 2016-12-11
    • 2017-02-12
    • 1970-01-01
    相关资源
    最近更新 更多