不能 return 从异步 AngularJS 工厂到控制器的结果

Can't return results from async AngularJS factory to controller

我已经阅读了很多博客文章和 Whosebug 答案,但我的工厂不会 return 将其结果发送给控制器。在controller中,我先做一个对象给工厂发送数据,然后调用工厂:

 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
};

首先我看到你使用应用工厂的方式不对/这和应用服务是一样的

在工厂中,你必须创建你的承诺,然后 return 到控制器,你将使用两个函数处理它;第一个是成功函数,第二个是错误

试试这段代码,你会更好地理解它

我从不使用 firebase 但我认为其他数据库也是如此

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();
});

我把 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 循环是一个函数。

工厂需要两个returns,在第二个和第三个函数中。第 4 个函数不需要 return,因为 videoWordsArray 在同一范围内,即可以从第 3 个嵌套函数访问。第三个嵌套循环必须 return 到第二个嵌套循环,return 到控制器。