无法将异步AngularJS工厂的结果返回到控制器

时间:2018-02-15 18:32:36

标签: angularjs angular-promise angularjs-factory

我已经阅读了十几篇博文和StackOverflow答案,但我的工厂不会将其结果返回给控制器。在控制器中,我首先创建一个对象将数据发送到工厂,然后调用工厂:

 let videoWordsArrayObject = { // make object to send data to factory
    clipInMovie: $scope.clipInMovie,
    movieTitle: $scope.movieTitle,
    userUID: $scope.user.uid,
    videoWords: $scope.videoWords
  };

videoWordsArrayFactory.toController(videoWordsArrayObject) // call factory
  .then(function(data) {
    console.log(data); // undefined
  })

data返回undefined。这是我的工厂:

app.factory('videoWordsArrayFactory', function($q) {

    function toController(videoWordsArrayObject) {

      let videoWordsArray = [];

      // get the data from the controller
      var clipInMovie = videoWordsArrayObject.clipInMovie;
      var userUID = videoWordsArrayObject.userUID;
      var videoWords = videoWordsArrayObject.videoWords;
      var movieTitle = videoWordsArrayObject.movieTitle;

      var qPromise = $q.when(firebase.database().ref('users').orderByChild('uid').equalTo(userUID).once('value')) // query Firebase Database by the user's UID to find the user's account
      .then(function(snapshot) { // get a snapshot of the user's data
      snapshot.forEach(function(childSnapshot) { // iterate through the user's data

      switch (true) { 

// cases that don't return data to the controller

      case childSnapshot.val()[movieTitle][movieTitle + "_" + clipInMovie][0].word === videoWords[0]: // array of completed words in Firebase with correct first element
      videoWordsArray = childSnapshot.val()[movieTitle][movieTitle + "_" + clipInMovie];
      console.log(videoWordsArray); // data is here
      return videoWordsArray;
      break;

      default:
      console.log("Error");
    } // close switch-case

  }); // close snapshot forEach loop
}) // close snapshot promise
.catch(function(error) {
  console.error('Error ', error);
}); // close snapshot catch
return qPromise; // no data here
}; // close toController

return {
  toController: toController
};

}); // close factory

工厂的return发生在数据从数据库返回之前。在对控制器执行return之前,我不明白如何让工厂等待承诺解决。

另外,我不明白toController: toController是什么。我知道键或值是控制器调用的函数,但为什么函数既是键又是值?我可以重构函数来摆脱

return {
  toController: toController
};

2 个答案:

答案 0 :(得分:0)

首先我看到你以错误的方式使用应用工厂/应用服务是同样的事情

在工厂,你必须创建你的承诺并返回控制器后,你将用两个功能处理它;第一个是成功函数,第二个是错误

尝试此代码,您将更好地理解

我从不使用firebase,但我认为考虑到其他dbs是一样的

app.factory('videoWordsArrayFactory', function($q) {
return {
    toController: toController
}
    function toController(videoWordsArrayObject) {
            return $q.when(firebase.database().ref('users').orderByChild('uid').equalTo(videoWordsArrayObject.userUID).once('value')) //this return a promise
    }

});


// in your controller
app.controller("myController",function("$scope, videoWordsArrayFactory"){

    var videoWordsArrayObject = { // make object to send data to factory
        clipInMovie: $scope.clipInMovie,
        movieTitle: $scope.movieTitle,
        userUID: $scope.user.uid,
        videoWords: $scope.videoWords
    };

    $scope.callPromise = function(){
        videoWordsArrayFactory.toController(videoWordsArrayObject).then(function(snapshot){
            //handle here youre logic after promise is resolved
            console.log(snapshot);
        },function(error){
            console.log(error);
        })
    }

    $scope.callPromise();
});

答案 1 :(得分:0)

我在错误的地方return。这是我工厂的工作代码:

app.factory('asyncVideoWordsArrayFactory', function($q) {

  return {
    toController: toController
  };

  function toController(asyncVideoWordsArrayObject) {
    var videoWordsArray = [];
    var clipInMovie = asyncVideoWordsArrayObject.clipInMovie;
    var movieTitle  = asyncVideoWordsArrayObject.movieTitle;
    var userUID     = asyncVideoWordsArrayObject.userUID;
    var videoWords  = asyncVideoWordsArrayObject.videoWords;

      var qPromise = $q.when(firebase.database().ref('users').orderByChild('uid').equalTo(userUID).once('value'))
      .then(function(snapshot) {

      snapshot.forEach(function(childSnapshot) {
        var userData = childSnapshot.val();

        switch (true) { 

        // cases for catching error conditions

        case userData[movieTitle][movieTitle + "_" + clipInMovie][0].word === videoWords[0]: 
        videoWordsArray = userData[movieTitle][movieTitle + "_" + clipInMovie];
        break;

        default:
        console.log("Error");
        } // close switch-case
      }); // close forEach loop
      return videoWordsArray; // return result to toController
    })  // close snapshot promise
    .catch(function(error) {
      console.log('Error: ' + error);
    });
    return qPromise;  // return result to controller
  } // close toController
}); // close factory

唯一的变化是将returncase内部(以及forEach循环内部)移动到forEach循环之外。显然,旧的(损坏的)代码未能将return结果从promise函数中删除,因此toController函数无法访问结果。

重新解决这个问题,有四个嵌套函数:

  1. 工厂是一个功能。
  2. toController是一个功能。
  3. 第二个承诺(.then)是一个函数。
  4. forEach循环是一个函数。
  5. 工厂需要两个returns,在第二和第三个功能中。第4个函数不需要返回,因为videoWordsArray在同一范围内,即可从第3个嵌套函数访问。第三个嵌套循环必须return到第二个嵌套循环,返回控制器。