0

I am working with an Angular controller that will add an undetermined amount of questions from one or more surveys uploaded to the server to an existing survey(s) with same name, that's just for understanding, the uploading, handling in back-end and returning response works flawlessly, the real problem here is the specific part of just uploading the new questions, which has the following functions:

//Will save next question
const next_question = function (response, this_survey, response_survey, sur_questions, question) {
    deferred = $q.defer();

    new_question = new QuestionsService();

    //Does a bunch of stuff with question object using all those arguments,
    //which is not relevant here

    if (check_existing_question(new_question, sur_questions)) {
        deferred.resolve();
    }
    else {
        new_question.$save({
            actsern: new_question.actsern
        }).then(function () {
            deferred.resolve();
        }).catch(function () {
            deferred.reject();
        });
    }

    return deferred.promise;

};

// Save the questions synchronously (wait for a promise to resolve/reject before saving next question)
async function save_question(response, this_survey, response_survey, sur_questions) {
    // I want to store all promises in an array and return for future error handling
    promises = [];
    for (const quest in response_survey) {
        // promise is undefined in console.log!!
        promise = await next_question(response, this_survey, response_survey, sur_questions, quest);
        console.log(promise);
        //Commented because if not returns error "promises.push is not a function"
        //promises.push(promise);
    }
    //Still undefined
    console.log(promise);
    return promise;
    //The above is how I managed to make it work but what I really want is:
    //return promises;
}

const set_survey_questions = function(response, this_survey, response_survey){

    //Never mind this, unrelated to my problem
    let sur_questions = QuestionsService.get({
        //this_survey is survey object that is being uploaded to, questions and surveys are linked through actsern
        actsern: this_survey.actsern
    });

    sur_questions.$promise.then(function () {

        promises = save_question(response, this_survey, response_survey, sur_questions);

        $q.all(promises).then(function () {
            console.log("Uploaded successfully all questions");
        }).catch(function (reason) {
            console.log(reason);
        });
    });
};

The thing is that I have to save the questions synchronously, wait for one to resolve/reject before saving the next, which is why I am using an async loop function. Everything works fine, the questions are uploaded one after the order, everything goes to the server exactly as it's supposed to. The problem is that I would like to get the promises of next_question() from the async function to deal with their errors in the future and do some other stuff after they all have been resolved using the $q.all(), but the problem is that as far as I know the await should return a promise but it just returns undefined and keeps as undefined even after the loop has finished and all promises, supposedly, resolve.

I know the function next_question() works fine because if it is called directly (outside of async function, directly from set_survey_questions()) it saves the question and returns the promise just as it's supposed.

I'm not very experienced with angular or even javascript for that matter so any help or improvement you can think of is welcome.

Nathan Danzmann
  • 105
  • 1
  • 2
  • 11
  • Try _declaring_ your variables: `const promises = []` and `const promise = await ...`. – JJWesterkamp Mar 26 '18 at 19:45
  • Avoid the [deferred antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Mar 26 '18 at 19:46
  • Don't return an array of promises. Call the `$q.all` right away! – Bergi Mar 26 '18 at 19:47
  • Yeah nevermind! – JJWesterkamp Mar 26 '18 at 19:48
  • @Bergi If I understood correctly you're pointing just an improvement and thanks for the tip, but the problem remains that the `await` is not returning any promise at all, it doesn't matter if I put in an array and return or just call `$q.all()` inside the function itself. – Nathan Danzmann Mar 26 '18 at 19:51
  • @NathanDanzmann Yes, those were just tips not answers. – Bergi Mar 26 '18 at 19:54

1 Answers1

1

As far as I know the await should return a promise but it just returns undefined

No. You should pass a promise to the await operator, it will then block execution of the async function until the promise is settled and return the result value of the promise.

The problem is that I would like to get the promises of next_question() from the async function to deal with their errors in the future

That doesn't seem to be compatible with your requirement of sequential saving. There are no multiple promises, there's only one active at a time. If any of them errors, the await will throw an exception and your loop will stop.

I think you really should simplify to

async function set_survey_questions(response, this_survey, response_survey) {
    let sur_questions = QuestionsService.get({
        actsern: this_survey.actsern
    });

    await sur_questions.$promise;
    try {
        for (const quest in response_survey) {
            await next_question(response, this_survey, response_survey, sur_questions, quest);
        }
        console.log("Uploaded successfully all questions");
    } catch (reason) {
        console.log(reason);
    }
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375