【问题标题】:AngularJS $scope.$apply() DilemmaAngularJS $scope.$apply() 困境
【发布时间】:2016-06-21 09:21:53
【问题描述】:

我正在使用 AngularJS 和 Firebase 实时数据库来创建一个跨设备同步的简单列表应用程序。网页客户端代码如下。

问题是我需要在我的 Firebase on('val') 回调中使用 $scope.$apply 函数,因为这个回调是从 AngularJS 外部执行的,没有它,绑定不会更新。但是,当用户输入一个新的列表项并单击“添加”按钮时,我看到了一个angular.js:12520 Error: [$rootScope:inprog]。我假设发生这种情况是因为当我已经在 $digest() 中时,我正在调用 $digest() 方法。

那么我怎样才能实现我想要做的事情呢?即在 AngularJS 之外触发回调时使用显式的 $digest() 方法,否则不要使用它。

<html>
    <head>
        <script src="https://www.gstatic.com/firebasejs/live/3.0/firebase.js"></script>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
    </head>
    <body>
        <script type="text/javascript">
            var config = {
                apiKey: "XXX",
                authDomain: "XXX",
                databaseURL: "XXX",
                storageBucket: "XXX",
            };
            firebase.initializeApp(config);
            var app = angular.module('myApp', []);
            app.controller('myCtrl', function($scope) {
                var database = firebase.database();
                database.ref().on('value', function(snapshot) {
                    $scope.$apply(function() {
                        $scope.items = [];
                        var result = snapshot.val();
                        for(var key in result) {
                            var listItem = result[key];
                            $scope.items.push(listItem);
                        }
                    });
                });
                $scope.addItem = function () {
                    database.ref().push().set($scope.addMe);
                }
            });
        </script>
        <div ng-app="myApp" ng-controller="myCtrl">
            <ul>
                <li ng-repeat="x in items">{{x}}</li>
            </ul>
            <input ng-model="addMe">
            <button ng-click="addItem()">Add</button>
        </div>
    </body>
</html>

【问题讨论】:

    标签: javascript angularjs firebase firebase-realtime-database


    【解决方案1】:

    修复 1 -

    使用

    $timeout(function(){ 
      $scope.$apply()
      ... write your code here 
    },0)
    

    当摘要循环完成时触发。

    修复 2 -

    如果摘要循环正在运行,$scope.$$phase 将返回 true,否则返回 false,但在您的情况下它不会有用,因为它不提供任何回调函数。

    也不推荐使用

    【讨论】:

    • 这是否可行,因为超时回调是在 AngularJS 范围之外执行的,因此确保对 $apply() 的调用不会引发错误?如果是这样,它似乎有点像一个黑客。这是在这种情况下推荐的方法吗?有没有我可以采用的设计模式来避免这种需要?
    • 不,它不是黑客。在控制器执行期间至少有 2 个摘要周期运行。一个是正常的,第二个摘要周期运行以确保是否有任何 $timeout?因此,如果我们在 $timeout 中写入任何内容,它会确保它在第一个摘要循环执行后运行。因此,如果我们想摆脱上述冲突,我认为这是一个完美的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-16
    • 1970-01-01
    • 2015-10-12
    相关资源
    最近更新 更多