【问题标题】:How to pass a callback function to once().then() in angularjs?如何在angularjs中将回调函数传递给once().then()?
【发布时间】:2016-10-23 13:12:33
【问题描述】:

我有一个单独的模型和一个用于教师列表的控制器。

我的teacherModel.js 是:

app.factory('Teacher', [function() {
   function Teacher(teacher) {
     // constructor
   };
   Teacher.prototype = {
        setTeacher: function(teacher) {
            angular.extend(this, teacher);
        },
        getAllTeachers: function(callback) {
            var scope = this;
            var ref = firebase.database().ref('/xxx/teachers');
            ref.once('value').then(function(snapshot) {
                teachersList = snapshot.val();
                scope.setTeacher(teachersList);
                // THERE'S A PROBLEM HERE...
                // I'm trying to pass this callback from the controller:
                callback;
            });
        }
    };  
    return Teacher;
}]);

现在我从我的控制器调用带有回调函数的getAllTeachers() 方法:

app.controller('teacherMainCtrl', ['$scope', 'Teacher', function($scope, Teacher){
    var teacher = new Teacher()
    teacher.getAllTeachers(function() {
       $scope.teachers = teacher;
       console.log($scope.teachers);
    });
}]);

问题是console.log($scope.teachers); 没有向控制台记录任何内容。我认为根本没有执行回调。

在从 Firebase 异步检索数据后,有人可以帮我找出我做错了什么,或者建议一种更好的方法来从控制器向模型数据添加功能吗?谢谢。

【问题讨论】:

  • 您可以简单地在 getAllTeachers() 中使用return ref.once('value);,因为它会返回一个承诺并取消回调,以便在您的控制器中,您只需调用 teacher.getAllTeachers().then(function ( snapshot) { // 分配快照});评估承诺的结果。

标签: javascript angularjs firebase callback firebase-realtime-database


【解决方案1】:

您可以利用 once 返回一个 firebase 承诺这一事实,以便您可以将代码更改为以下内容:

app.factory('Teacher', [function() {
   function Teacher(teacher) {
     // constructor
   };
   Teacher.prototype = {
        setTeacher: function(teacher) {
            angular.extend(this, teacher);
        },
        getAllTeachers: function() {
            var scope = this;
            var ref = firebase.database().ref('/xxx/teachers');
            return ref.once('value').then(function(snapshot) {      
                return snapshot.val();
            });
        }
    };  
    return Teacher;
}]);

这将类似于任何返回承诺的$http 请求。现在,在您的控制器中,您可以像这样调用getAllTeachers()

app.controller('teacherMainCtrl', ['$scope', 'Teacher', function($scope, Teacher){
    var teacher = new Teacher()
    teacher.getAllTeachers().then(function (snapshotValues) {
        // What you returned in the promise above is populated in snapshotValues here
        $scope.teachers = snapshotValues;
    });
}]);

更新

如果您想在特定场景中使用$q 服务,您可以执行以下操作:

app.factory('Teacher', ['$q', function($q) {
   function Teacher(teacher) {
     // constructor
   };
   Teacher.prototype = {
        setTeacher: function(teacher) {
            angular.extend(this, teacher);
        },
        getAllTeachers: function() {
            var defer = $q.defer();
            var scope = this;
            var ref = firebase.database().ref('/xxx/teachers');
            ref.once('value').then(function(snapshot) {      
                var val = snapshot.val();
                // Transform your data any way you want. 
                // Whatever you pass into resolve() will be available as a parameter in the subsequent then()

                defer.resolve(val);
            });

            return defer.promise;
        }
    };  
    return Teacher;
}]);

使用方法还是一样的。您只需拨打then()

teacher.getAllTeachers()
    .then(function (whatYouPassedInResolve) {

});

另外需要注意的是,在您工厂内部的getAllTeachers 方法中,我没有处理任何错误情况。这将通过使用defer.reject(objectToSendBack) 拒绝承诺来实现。当您认为调用失败时,您可以传入任何想要访问的数据。

只需将第二个参数的函数传递给 `then(successCallback, errorCallback) 以处理任何被拒绝的承诺。

【讨论】:

  • 谢谢约翰。这可行,但是,我试图避免控制器对 firebase 的任何依赖。因此,如果我的数据存储发生更改,我可以随时更改模型并接受回调。例如,我真的想向控制器返回一个数组或一个已处理的对象,而不是默认的 firebase 'snapshot' 响应。
  • 我建议然后使用$q 服务创建一个延迟对象并将其作为承诺返回。然后,您可以解决或拒绝您的 firebase 请求的结果(或像您提到的返回数组的预处理)。然后,在返回一个有角度的内置承诺对象(与$http 相同)时规范化行为。这样,您的服务的调用者正在评估 $q 承诺,而对底层服务调用一无所知。
  • 嗨,约翰,这似乎更好。我以前没有使用过$q 服务。我会检查一下。谢谢。也许您可以编辑答案以包含此内容?我认为它会对其他人有更多帮助。
  • @Sadeep 不用担心。我更新了答案以包括使用$q
【解决方案2】:

我认为你实际上并没有调用回调,使用callback()

app.factory('Teacher', [function() {
   function Teacher(teacher) {
     // constructor
   };
   Teacher.prototype = {
        setTeacher: function(teacher) {
            angular.extend(this, teacher);
        },
        getAllTeachers: function(callback) {
            var scope = this;
            var ref = firebase.database().ref('/xxx/teachers');
            ref.once('value').then(function(snapshot) {
                teachersList = snapshot.val();
                scope.setTeacher(teachersList);
                // THERE'S A PROBLEM HERE...
                // Try this
                callback();
            });
        }
    };  
    return Teacher;
}]);

【讨论】:

  • 感谢您的回答。我确实错过了括号。
猜你喜欢
  • 2014-07-13
  • 2019-04-13
  • 2016-03-02
  • 2013-06-06
  • 1970-01-01
  • 2015-07-27
  • 1970-01-01
  • 1970-01-01
  • 2013-02-07
相关资源
最近更新 更多