如何在Angular模板中显示Observable <any []>的一个值,直到下一次单击

时间:2017-09-04 02:06:22

标签: angular firebase rxjs

目标:我有一个测验组件,我希望能够在我的模板中一次显示一个问题。用户单击“下一步”按钮时可以显示下一个问题。

问题:我有一个包含整个问题列表的FirebaseListObservable。如何一次只渲染一个模板。到目前为止,我粘贴到了我的代码之下。它呈现整个列表。我不知道从哪里开始,部分原因在于我初学者的RxJS知识水平。

import { Component, OnInit } from '@angular/core';
import { FirebaseService } from '../../firebase.service';
import { Observable } from 'rxjs/Observable';
import { Question } from '../../model/question';

@Component({
  selector: 'app-quiz',
  template: `
    <md-grid-list cols="1" rowHeight="2:1">
      <md-grid-tile>
        <md-card *ngFor="let question of questions$ | async">
          <md-card-header>
            <md-card-title>{{question?.course}}</md-card-title>
            <md-card-subtitle>{{question?.chapter}}</md-card-subtitle>
          </md-card-header>
          <md-card-content>
            <p>{{question?.question}}</p>
          </md-card-content>
          <md-card-actions>
            <button md-button>See Answer</button>
            <button (click)="nextQuestion(question)" md-button>Next 
Question</button>            
          </md-card-actions>
        </md-card>
      </md-grid-tile>
    </md-grid-list> 
  `,
  styles: [`.example-card { width: 400px;}`]
})
export class QuizComponent implements OnInit {

  questions$: Observable<Question[]>;

  constructor(private fbDatabase: FirebaseService) { }

  ngOnInit() {
    this.questions$ = this.fbDatabase.getFirebaseList('/questions');
  }

  nextQuestion() {
  }

}

2 个答案:

答案 0 :(得分:1)

首先,我通过创建一个显示一个问题的组件来利用组件模式:

import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';

export interface IQuestion {
  label: string;
  answers: string[];
}

@Component({
  selector: 'app-question',
  template: `
    <div>
      <b>Question:</b>
      <p>{{ question.label }}</p>

      <b>Possible answers</b>
      <p *ngFor="let answer of question.answers">{{ answer }}</p>      
    </div>
  `,
  styles: [``],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppQuestionComponent {
  @Input() question: IQuestion;
}

然后,AppComponent的代码及其评论足以理解我认为:
TS代码

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  question$: Observable<IQuestion>;
  questions$: Observable<IQuestion[]>;

  _click$ = new Subject<void>();
  click$ = this._click$.startWith(null);

  constructor(private firebaseService: FirebaseService) { }

  ngOnInit() {
    // get the questions from firebase
    this.questions$ = this
      .firebaseService
      .getFirebaseList('your-list')
      // add a false statement so we know when to ends
      .map(questions => [...questions, false]);

    const questionsOneByOne$ = this
      .questions$
      .mergeMap(
        questions =>
          questions.map(
            // explode each question to a different stream value...
            question => Observable.of(question)
          )
      )
      // ...so we can get them one by one
      .concatAll();

    this.question$ = Observable
      .zip(questionsOneByOne$, this.click$)
      .map(([question, _]) => question);
  }

  nextQuestion() {
    this._click$.next();
  }
}

HTML代码

<div *ngIf="question$ | async as question; else noMoreQuestions">
  <app-question [question]="question"></app-question>

  <button (click)="nextQuestion()">Go to next question</button>
</div>

<ng-template #noMoreQuestions>
  No more questions
</ng-template>

这是Stackblitz上的现场演示(带有模拟的火力列表)
https://stackblitz.com/edit/angular-mbnscx

如果您有其他问题,请告诉我们;)

答案 1 :(得分:0)

如果您不想显示以前的问题,则应该一次渲染问题数组的每个项目(问题对象)。 我将添加一个新的可观察变量类型Question以呈现给视图。用于跟踪数组中项目的索引变量。类似的东西:

@Component({
      selector: 'app-quiz',
      template: `
        <md-grid-list cols="1" rowHeight="2:1">
          <md-grid-tile>
            <md-card *ngIf="question | async">
              <md-card-header>
                <md-card-title>{{(question | async)?.course}}</md-card-title>
                <md-card-subtitle>{{(question | async)?.chapter}}</md-card-subtitle>
              </md-card-header>
              <md-card-content>
                <p>{{(question | async)?.question}}</p>
              </md-card-content>
              <md-card-actions>
                <button md-button>See Answer</button>
                <button (click)="nextQuestion(index + 1)" md-button>Next 
    Question</button>            
              </md-card-actions>
            </md-card>
          </md-grid-tile>
        </md-grid-list> 
      `,
      styles: [`.example-card { width: 400px;}`]
    })

    export class QuizComponent implements OnInit {

      questions: Array<Question>;

      question: Observable<Question>;
      index: number = 0;

      constructor(private fbDatabase: FirebaseService) { }

      ngOnInit() {
          this.fbDatabase.getFirebaseList('/questions').subscribe((res) =>{
              if(res) {
                console.log(res);
                this.questions = res;
                this.question = this.nextQuestion(index);
              }
          });

      }

      nextQuestion(i: number): Observable<Question> {
          if i >= this.questions.length {
            i = 0;
          }

          return Observable.of(this.questions[i]);
      }

    }

请告诉我这是否适合您?