为什么需要角度$申请?

时间:2014-05-09 16:01:42

标签: angularjs data-binding breeze

请考虑控制器的以下angularjs代码:

(function (app) {
    var controller = function ($scope, $state, datacontext) {
        $scope.$parent.manageTitle = "Account Management";
        $scope.accounts = [];

        var init = function () {
            getRecords();
        };

        var getRecords = function () {
            return datacontext.getAccounts().then(function (data) {
                $scope.$apply(function () {
                    $scope.accounts = data;
                });
            });
        };

        init();
    };

    app.controller("accountsCtrl", ["$scope", "$state", "datacontext", controller]);
})(angular.module("app"));

删除$ scope。$ apply包装器并在getRecords方法中只留下“$ scope.accounts = data”会破坏代码。检索数据但html中的ng-repeat指令不会自动更新。我试图让我的手臂围绕整个$ apply / $ digest模型,但在这种情况下,似乎不应该要求$ apply。

我做错了吗?

感谢。

< ------------------------------------------编辑 - -------------------------------------->

好的,谢谢你的回复。这是datacontext。它使用Breeze。我仍然无法弄清楚问题是什么 - 我只是不明白为什么在上面的代码中需要$ apply。

(function (app) {
    var datacontext = function () {
        'use strict';
        breeze.config.initializeAdapterInstance('modelLibrary', 'backingStore', true);
        breeze.config.initializeAdapterInstance("ajax", "angular", true);
        breeze.NamingConvention.camelCase.setAsDefault();

        var service;
        var manager = new breeze.EntityManager('api/ProximityApi');
        var entityQuery = breeze.EntityQuery;

        var queryFailed = function (error) {
        };

        var querySuccess = function (data) {
            return data.results;
        };

        var getAccounts = function () {
            var orderBy = 'accountName';
            return entityQuery.from('Accounts')
                .select('id, accountName')
                .orderBy(orderBy)
                .using(manager)
                .execute()
                .then(querySuccess, queryFailed);
        };

        service = {
            getAccounts: getAccounts
        };

        return service;
    };
    app.factory('datacontext', [datacontext]);
})(angular.module('app'));

再次感谢!

2 个答案:

答案 0 :(得分:3)

感谢您的回答。杰瑞德 - 你是对的钱。默认情况下,Breeze不使用角度$ q承诺,而是使用第三方Q.js承诺。因此,我需要$ apply来将VM同步到视图。然而,最近,Breeze人员创建了angular.breeze.js,它允许Breeze代码使用角度承诺。通过在应用程序中包含angular.breeze模块,所有Breeze代码都将使用原生角度承诺和$ http。

这解决了我的问题,我可以删除$ apply电话。

请参阅:http://www.breezejs.com/documentation/breeze-angular-service

答案 1 :(得分:1)

您需要使用$ apply函数的原因是使用Breeze返回数据的结果。 $ apply函数用于获取角度以在所有内部监视上运行摘要并相应地更新范围。当角度范围内发生所有更改时,不需要这样做,因为它会自动进行摘要。在你的代码中,因为你正在使用Breeze,所以更改发生在角度范围之外,因此你需要获得角度来手动运行摘要,这对于在angular(jQuery,其他框架)之外发生的任何事情都是如此。等...)。确实,Breeze使用promises来更新数据,但Angular在promise返回后不知道如何处理更改,因为它超出了范围。如果您使用带有promise的角度服务,则视图将自动更新。如果你的代码工作正常,那么以这种方式使用$ apply是正确的方法。

我唯一可能建议的是改变你调用apply的方式,以确保它只在另一个摘要当前没有进行时才会运行,因为这会导致摘要错误。我建议你这样称呼函数:

if(!$scope.$$phase){$scope.$apply(function () {
   $scope.accounts = data;
});

或者另一种选择是围绕$ apply函数编写一个自定义包装器,如SafeApply