简体   繁体   中英

How to wait until post method finished Angular

I am working on Knowledge Testing System, so as an admin I can create tests. On the page where I create tests, first of all I enter info about test and count of questions. Then for every question I enter count of answers for this question and info about question. Then for every answer I enter some info and then I click on submit button.

Order of actions must be as follows:

Post test -> Post first question -> Post answers for first questions - > Post second question and etc.

So I need to wait until first question created, then create every answer for this question and only then create second question and answers for it.

Order is very important and must be as I wrote.

But I have a mistake, my order is not working as I want because of my post methods work asynchronous.

For example, if I create 2 questions and 2 answers for each questions my order turns in this:

Post Test finished -> Post Question 2 finished - > Post Question 1 finished - > Post all answers finished

So I need to know, how to wait until post method finished.

Here is my method where I post questions and answers for them:

for(let item of this.sas){// sas is type Map<Question, Answer[]>
      // get question info
      let q = document.getElementById(`q_${ii+1}`) as HTMLInputElement;
      let t = document.getElementById(`t_${ii+1}`) as HTMLInputElement;
      let isSin = true;
      if(t.checked){
        isSin = false;
      }
      let question = new Question();
      question.Content = q.value;
      question.IsSingle = isSin;
      //

      // get answers for this question
      let answers = [];
      for(let j of item[1]){
        let isCorrect = document.getElementById(`a_isCorrect_${ii}:${j}`) as unknown as HTMLInputElement;
        let content = document.getElementById(`a_content_${ii}:${j}`) as unknown as HTMLInputElement;
        let mark =  document.getElementById(`a_mark_${ii}:${j}`) as unknown as HTMLInputElement;

        let answer = new Answer();
        answer.IsCorrect = isCorrect.checked;
        answer.Content = content.value;
        answer.Mark = Number(mark.value);
        answers.push(answer);
        j++;
      }

      //post question
      this.questionService.createQuestion(question).subscribe(data=> {
        console.log(`question ${question.Content} done`);
      //

         //post answers for question
           from(answers).pipe(
             map(answer => this.answerService.createAnswer(answer).subscribe(data => { 
                          console.log(`answer ${answer} done` ) } ) )
           ).subscribe(s=> { console.log("done")});
      //
      });
      ii++;
    };
  }

I believe your best bet, AS LONG AS YOU DON'T NEED TO POST A BUNCH , is probably something recursive like so:

function handleQuestion(item, index = 0) {
let q = document.getElementById(`q_${index+1}`) as HTMLInputElement;
let t = document.getElementById(`t_${index+1}`) as HTMLInputElement;
let isSin = true;
if(t.checked){
    isSin = false;
}
let question = new Question();
question.Content = q.value;
question.IsSingle = isSin;

let answers = [];
for(let j of item){
    let isCorrect = document.getElementById(`a_isCorrect_${index}:${j}`) as unknown as HTMLInputElement;
    let content = document.getElementById(`a_content_${index}:${j}`) as unknown as HTMLInputElement;
    let mark =  document.getElementById(`a_mark_${index}:${j}`) as unknown as HTMLInputElement;

    let answer = new Answer();
    answer.IsCorrect = isCorrect.checked;
    answer.Content = content.value;
    answer.Mark = Number(mark.value);
    answers.push(answer);
    j++;
}

this.questionService.createQuestion(question).subscribe(data=> {
    from(answers).pipe(
    map(answer => this.answerService.createAnswer(answer).subscribe(data => { 
        console.log(`answer ${answer} done` ) } ) )
    ).subscribe(s=> {
        index++;
        if (this.sas[index]) {
            handleQuestion(this.sas[index], index);
        }
    });
}); }

You may combine two observables... to reach the response data when both have responded already.

fetchData(): Observable<any[]> {
    return combineLatest(
        this.observable1$(),
        this.observable2$()
    );
}

You need to use concatMap here, it will wait step by step for every emit.

//post question
this.questionService.createQuestion(question).pipe(
    // executes answers only when question emits.
    concatMap(data=> {
        console.log(`question ${question.Content} done`);
        //

        //post answers for question
        return from(answers).pipe(
            concatMap(answer => this.answerService.createAnswer(answer).pipe(
                tap(data => console.log(`answer ${answer} done` ) ),
            )),
            finalize(() => console.log("done")),
        );
    }),
).subscribe();

if you want the whole thing:

let ii = 0;
from(this.sas).pipe(
    contactMap(item => {
        // get question info
        let q = document.getElementById(`q_${ii+1}`) as HTMLInputElement;
        let t = document.getElementById(`t_${ii+1}`) as HTMLInputElement;
        let isSin = true;
        if(t.checked){
            isSin = false;
        }
        let question = new Question();
        question.Content = q.value;
        question.IsSingle = isSin;
        //

        // get answers for this question
        let answers = [];
        for(let j of item[1]){
            let isCorrect = document.getElementById(`a_isCorrect_${ii}:${j}`) as unknown as HTMLInputElement;
            let content = document.getElementById(`a_content_${ii}:${j}`) as unknown as HTMLInputElement;
            let mark =  document.getElementById(`a_mark_${ii}:${j}`) as unknown as HTMLInputElement;

            let answer = new Answer();
            answer.IsCorrect = isCorrect.checked;
            answer.Content = content.value;
            answer.Mark = Number(mark.value);
            answers.push(answer);
            j++;
        }
        ii++;

        //post question
        return this.questionService.createQuestion(question).pipe(
            // executes answers only when question emits.
            concatMap(data=> {
                console.log(`question ${question.Content} done`);
                //

                //post answers for question
                return from(answers).pipe(
                    concatMap(answer => this.answerService.createAnswer(answer).pipe(
                        tap(data => console.log(`answer ${answer} done` ) ),
                    )),
                    finalize(() => {
                        console.log("done");
                    ),
                );
            }),
        );
    }),
    finalize(() => {
      // call done function here.
    ),
).subscribe();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM