I've read a dozen blog posts and StackOverflow answers but my factory won't return its results to the controller. In the controller, I first make an object to send data to the factory, then call the factory:
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
})
The data
comes back undefined
. Here's my factory:
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
The return
from the factory happens before the data comes back from the database. I don't understand how to make the factory wait for the promise to resolve before doing the return
to the controller.
Also, I don't understand what toController: toController
is. I know that either the key or the value is the function that the controller calls, but why is the function both the key and the value? Can I refactor the function to get rid of
return {
toController: toController
};
I had return
in the wrong place. Here's my working code for the factory:
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
The only change was moving the return
from inside the case
(and inside the forEach
loop) to outside the forEach
loop. Apparently the old (broken) code failed to return
the result out of the promise function, so the toController
function didn't have access to the result.
Rephrasing the issue, there are four nested functions:
toController
is a function..then
) is a function.forEach
loop is a function.The factory needs two returns
, in the 2nd and 3rd functions. No return is needed in the 4th function because videoWordsArray
is on the same scope, i.e., is accessible from the 3rd nested function. The 3rd nested loop has to return
to the 2nd nested loop, which returns to the controller.