angular - Utföra avancerade HTTP-förfrågningar i rxjs


Jag har följande objekt:

class Question {
    idQuestion: string;
    question: string;
    typeQuestion: string;
}

class Answer {
    idAnswer: string;
    idQuestion: string;
    answer: string;
}

class Option {
    idOption: string;
    idQuestion: string;
    option;
}

Och jag vill fylla följande objekt:

class QuestionOptionsAnswer {
    question: Question;
    answer: Answer;
    options: Option[];
}

För tillfället har jag en tjänst för varje typ av objekt, så vi kan illustrera det på följande sätt:

questionService.getQuestions();
answerService.getAnswers();
optionService.getOptions();

För att fylla ett questionoptionsanswer-objekt har jag gjort nästlade förfrågningar:

questionService.getQuestions()
    .subscribe(
        answerService.getAnswers()
           .subscribe(
               optionService.getOptions()
                  .subscribe();
           )
    )

Jag kan fylla i questionoptionsanswer-objektet korrekt, men det går långsamt, så jag tror att jag gör ett dåligt tillvägagångssätt. Idén bakom att ha ett questionoptionsanswer är för att på ett enkelt sätt rendera html med Angular2-direktiv.

Jag läste om flatMap, switchMap, forkJoin men jag är inte riktigt säker på hur man använder dem.

Vilket skulle kunna vara ett bra sätt att ladda denna data?

questionoptionsanswer kommer att ha ett frågeobjekt, ett svar kopplat till det och dess möjliga alternativ beroende på typeQuestion t.ex: select, radio, multiple, etc.

Svar #1

Så du behöver ringa det första anropet och vänta på dess svar och sedan ringa de två andra anropen (för alternativ och svaret) samtidigt.

Eftersom jag vill veta när båda svaren är klara kommer jag att använda Observable.forkJoin()-operatorn som sänder en enda array med alla värden från käll-Observables när de är färdiga och sedan lägga till data i qoa-variabeln som jag bara kommer att skicka till Observers när den prenumererar.

Operatorer såsom concat() eller concatMap() är bra för att göra flera HTTP-anrop i ordning men inte särskilt användbara när du behöver skapa flera Observable för att konstruera ett stort svar som du vill emitera (QuestionOptionsAnswer i ditt fall).

Jag använde också Observable.of(...) för att simulera HTTP-förfrågningar. Jag vet inte vad ditt användningsfall är, så du kommer kanske inte att använda Observable.create() och använda Subject istället:

function getQOA() {
    return Observable.create(observer => {

        Observable.of({ question_id: '1' }).subscribe(response => {
            var qoa = new QuestionOptionsAnswer();
            let question = new Question();
            question.idQuestion = response.question_id;

            qoa.question = question;

            let obs1 = Observable.of({ answer_id: '1', answer: 'bla' });
            let obs2 = Observable.of([{ option_id: '1', option: 'ble' }]);

            Observable.forkJoin(obs1, obs2).subscribe(responses => {
                let [answerResponse, optionsResponse] = responses;

                let answer = new Answer();
                answer.idAnswer = answerResponse.answer_id;
                answer.answer = answerResponse.answer;
                qoa.answer = answer;

                qoa.options = optionsResponse.map(o => {
                    let option = new Option();
                    option.idOption = o.option_id;
                    option.option = o.option;
                    return option;
                });

                observer.next(qoa);
            });
        });
    });
}

getQOA().subscribe(qoa => console.log(qoa));

Skriver ut till konsolen:

QuestionOptionsAnswer {
  question: Question { idQuestion: '1' },
  answer: Answer { idAnswer: '1', answer: 'bla' },
  options: [ Option { idOption: '1', option: 'ble' } ] }