1

我正在构建一个 AngularJS 应用程序(使用 1.2.0 RC1),它使用 REST API 来保存用户输入的数据。用户将输入有关公司的数据,它由我需要保存的两个核心组件组成:

  • 公司详情
  • 该公司内的联系人

我有 1 个 REST 方法可以调用来保存公司,然后我有另一种方法可以调用来保存每个联系人。

我计划使用它$q来跟踪所有请求并在完成后解决它们。

我遇到的问题是,虽然 REST API 被成功调用并且我的所有数据都被保存,但当我单击屏幕上的按钮(例如按钮)之前add contact,当所有承诺都解决时,我的控制器不会收到通知。我已经尝试消除 REST API 作为问题的根源,但是在使用setTimeout.

这是我的service模块:

angular.module('myApp', ['restService'])
    .factory('service', ['client', '$q', function (client, $q) {
        return {
            create: function (name, people) {
                var deferred = $q.defer();

                setTimeout(function () {
                    console.log('saved company ' + name);

                    var promises = people.map(function (person) {
                        var dfd = $q.defer();

                        setTimeout(function () {
                            console.dir(person);
                            console.log('Person saved');
                            dfd.resolve();
                        }, 100);

                        return dfd.promise;
                    });

                    $q.all(promises).then(deferred.resolve);
                }, 100);

                return deferred.promise;
            }
        };
    }]);

这是我的控制器:

angular.module('club', ['myApp'])
    .controller('RegisterCtrl', ['$scope', 'service', function ($scope, service) {
        $scope.addPerson = function () {
            $scope.company.people.push({
                firstName: '',
                lastName: '',
                email: ''
            });
        };

        $scope.removePerson = function (person, index) {
            $scope.company.people.splice(index, 1);
        };

        $scope.save = function (company) {
            service.createClub(company.name, company.people).then(function () {
                console.log('And we\'re done');
            });
        };

        $scope.company = {
            name: '',
            people: []
        };
    }]);

因此,当我调用该save方法(ng-click绑定到按钮)时,我将设置一个 console.log,如下所示:

saved company
Object
Person saved
Object
Person saved

注意没有And we're done输出。一旦我单击绑定到的按钮,我就会得到最终的消息输出addPersonng-click

4

3 回答 3

2

Angular 不会神奇地监视所有超时。它需要一个钩子来告知某些事情可能已经改变,这会触发一个$digest循环。

您可以通过调用$scope.$apply()或使用内置处理程序(如ng-click)手动完成。但是对于这个用例$timeout,您还可以使用服务来代替setTimeout.

请参阅API 参考/ng/$timeout

于 2013-08-22T07:45:11.123 回答
0

您总是希望在作用域上下文中调用 deferred.resolve() 和 deferred.reject()。在您的情况下,您正在从角度框架之外调用代码(setTimeout,并且实际使用您在评论中提到的用于 Azure 移动服务的 JS 客户端 API),因此您应该将 dfd.resolve() 包装在 $rootScope 中。 $apply() (不要忘记将 $rootScope 注入您的服务)。

http://plnkr.co/edit/3sCHEjrtMdqCvFQ7ILTD

这个 Plunkr 显示了一个工作示例。如果您将 $rootScope.$apply(dfd.resolve()) 更改回 dfd.resolve(),它就会出现您在问题中描述的问题。

请注意,由于本文中列出的原因,使用 $rootScope.$apply(function(){dfd.resolve()}) 可能也更好:

http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

于 2013-09-01T03:32:36.783 回答
0

强烈建议使用 AngularJS$http服务与您的 REST API 进行通信,因为它会为您更新模型。

它返回一个可以链接successerror处理程序的承诺,因此它非常通用。

翻译成你的代码,你可以有这样的服务:

angular.module('myApp', [])
    .factory('person', ['$http', function ($http) {
        return {
            create: function (data) {

                // Return promise
                return $http.post('/yourApiUrl', data);
            }
        };
    }]);

和这样的控制器:

angular.module('myApp', [])
    .controller('yourController', ['person', function (person) {

        $scope.company = {
            name: '',
            people: []
        };

        $scope.addPerson = function(data){

            //Save person to API
            person.create(data)

                // Success handler
                .success(function(data, status, headers, config) {

                    // Parse person from response (e.g. if your API 
                    // returns the created object after a POST)
                    var person = data;

                    // Add person to company
                    $scope.company.people.push(person)
                })

                // Error handler
                .error(function(data, status, headers, config) {

                    // Handle error
                });

        };

    }]);

通过从您的服务返回承诺,您可以自定义控制器中的successerror处理程序,从而实现非常灵活的解决方案。

而且您不必创建自己的承诺。AngularJS 将为您处理这一切。

我希望这会有所帮助!

于 2013-08-22T07:59:14.280 回答