如何在 Angular 中显示 Observable-Array 的一个 Observable?
How to display one Observable of an Observable-Array in Angular?
我有一个包含问题列表的 Observable-Array。我想一个一个地展示我的问题,但找不到办法。
到目前为止,我只在 html.
中用 *ngFor 显示了所有这些
这是我的组件:
import { Component, OnInit } from '@angular/core';
import { mergeMap, Observable, of, concatAll, Subject, startWith, zip, Subscription } from "rxjs";
import { Question } from "../models/Question";
import { QuestionService } from "../services/question.service";
import { AuthService } from "../services/auth.service";
import { User } from "../models/User";
@Component({
selector: 'app-play',
templateUrl: './play.component.html',
styleUrls: ['./play.component.css']
})
export class PlayComponent implements OnInit {
user_id: Pick<User, "id"> | undefined
unanswered_questions$: Observable<Question[]> | undefined
question$: Observable<Question> | undefined
constructor(
private questionService: QuestionService,
private authService: AuthService
) { }
ngOnInit(): void {
this.user_id = this.authService.userId
this.unanswered_questions$ = this.getUnansweredQuestions(this.user_id)
}
getUnansweredQuestions(user_id: Pick<User, "id"> | undefined): Observable<Question[]> {
return this.questionService.fetchAllUnansweredQuestions(user_id);
}
}
这是我的 html:
<mat-card class="question-card" *ngFor="let question of unanswered_questions$ | async">
<mat-card-header>
<div mat-card-avatar class="example-header-image"></div>
<mat-card-title>{{question.title}}</mat-card-title>
</mat-card-header>
<mat-card-content>
<h3>{{question.body}}</h3>
</mat-card-content>
<mat-card-actions>
<button mat-button>{{question.answer1}}</button>
<button mat-button>{{question.answer2}}</button>
<button mat-raised-button color="accent">Skip<mat-icon>skip_next</mat-icon></button>
</mat-card-actions>
</mat-card>
我发现 this Post 有人在尝试做基本相同的事情。不幸的是,post 的两个答案都不适合我。我认为它们不起作用,因为 post 已经 4 岁了,而我使用的是更新版本的 rxjs 和 angular.
非常感谢任何帮助。谢谢!
您可以使用不同的解决方法来做到这一点。只要定义一个变量currentQuestionNumber =1
;
然后检查这个变量是否匹配HTML
中的index+1
<mat-card
class="question-card"
*ngFor="let question of unanswered_questions$ | async; let i = index"
>
<ng-container *ngIf="currentQuestionNumber === i + 1">
<mat-card class="question-card">
<mat-card-header>
<div mat-card-avatar class="example-header-image"></div>
<mat-card-title>{{ question.title }}</mat-card-title>
</mat-card-header>
<mat-card-content>
<h3>{{ question.body }}</h3>
</mat-card-content>
<mat-card-actions>
<button mat-button>{{ question.answer1 }}</button>
<button mat-button>{{ question.answer2 }}</button>
<button mat-raised-button color="accent">
Skip<mat-icon>skip_next</mat-icon>
</button>
</mat-card-actions>
</mat-card>
</ng-container>
</mat-card>
然后在“跳过”和“下一步”按钮上添加点击处理程序,以在每次点击时递增或递减 currentQuestionNumber
。
目前你的代码“有效”,因为你正在将你的 observable 传递给异步管道处理程序,该处理程序会一直执行 ngFor,直到 observable 被解析。
我会更改您的代码,以便您订阅 observable 并处理随后的结果。实际上,我会先转换为承诺并等待它,因为在我看来,这种风格更具可读性和可预测性,尤其是对于“一劳永逸”的事件。
所以像这样更改您的组件(注意:为了简洁起见,我省略了导入和装饰器):
export class PlayComponent implements OnInit {
user_id: Pick<User, "id"> | undefined;
unanswered_questions: Question[];
question$: Observable<Question> | undefined;
questionIndex = 0;
constructor(
private questionService: QuestionService,
private authService: AuthService
) { }
async ngOnInit(): Promise<void> {
this.user_id = this.authService.userId;
await this.unanswered_questions = this.getUnansweredQuestions(this.user_id).toPromise();
}
getUnansweredQuestions(user_id: Pick<User, "id"> | undefined): Observable<Question[]> {
return this.questionService.fetchAllUnansweredQuestions(user_id);
}
skipQuestion(): void {
if (this.questionIndex !== this.getUnansweredQuestions.length) {
this.questionIndex++;
}
}
}
然后是你的 HTML:
<mat-card class="question-card" *ngIf="unanswered_questions">
<mat-card-header>
<div mat-card-avatar class="example-header-image"></div>
<mat-card-title>{{unanswered_questions[questionIndex].title}}</mat-card-title>
</mat-card-header>
<mat-card-content>
<h3>{{unanswered_questions[questionIndex].body}}</h3>
</mat-card-content>
<mat-card-actions>
<button mat-button>{{unanswered_questions[questionIndex].answer1}}</button>
<button mat-button>{{unanswered_questions[questionIndex].answer2}}</button>
<button mat-raised-button color="accent" (click)="skipQuestion()">Skip<mat-icon>skip_next</mat-icon></button>
</mat-card-actions>
</mat-card>
通过将 ngIf 添加到您的 matCard 中,您可以在解析 observable 之前阻止渲染。
我有一个包含问题列表的 Observable-Array。我想一个一个地展示我的问题,但找不到办法。
到目前为止,我只在 html.
中用 *ngFor 显示了所有这些这是我的组件:
import { Component, OnInit } from '@angular/core';
import { mergeMap, Observable, of, concatAll, Subject, startWith, zip, Subscription } from "rxjs";
import { Question } from "../models/Question";
import { QuestionService } from "../services/question.service";
import { AuthService } from "../services/auth.service";
import { User } from "../models/User";
@Component({
selector: 'app-play',
templateUrl: './play.component.html',
styleUrls: ['./play.component.css']
})
export class PlayComponent implements OnInit {
user_id: Pick<User, "id"> | undefined
unanswered_questions$: Observable<Question[]> | undefined
question$: Observable<Question> | undefined
constructor(
private questionService: QuestionService,
private authService: AuthService
) { }
ngOnInit(): void {
this.user_id = this.authService.userId
this.unanswered_questions$ = this.getUnansweredQuestions(this.user_id)
}
getUnansweredQuestions(user_id: Pick<User, "id"> | undefined): Observable<Question[]> {
return this.questionService.fetchAllUnansweredQuestions(user_id);
}
}
这是我的 html:
<mat-card class="question-card" *ngFor="let question of unanswered_questions$ | async">
<mat-card-header>
<div mat-card-avatar class="example-header-image"></div>
<mat-card-title>{{question.title}}</mat-card-title>
</mat-card-header>
<mat-card-content>
<h3>{{question.body}}</h3>
</mat-card-content>
<mat-card-actions>
<button mat-button>{{question.answer1}}</button>
<button mat-button>{{question.answer2}}</button>
<button mat-raised-button color="accent">Skip<mat-icon>skip_next</mat-icon></button>
</mat-card-actions>
</mat-card>
我发现 this Post 有人在尝试做基本相同的事情。不幸的是,post 的两个答案都不适合我。我认为它们不起作用,因为 post 已经 4 岁了,而我使用的是更新版本的 rxjs 和 angular.
非常感谢任何帮助。谢谢!
您可以使用不同的解决方法来做到这一点。只要定义一个变量currentQuestionNumber =1
;
然后检查这个变量是否匹配HTML
中的index+1 <mat-card
class="question-card"
*ngFor="let question of unanswered_questions$ | async; let i = index"
>
<ng-container *ngIf="currentQuestionNumber === i + 1">
<mat-card class="question-card">
<mat-card-header>
<div mat-card-avatar class="example-header-image"></div>
<mat-card-title>{{ question.title }}</mat-card-title>
</mat-card-header>
<mat-card-content>
<h3>{{ question.body }}</h3>
</mat-card-content>
<mat-card-actions>
<button mat-button>{{ question.answer1 }}</button>
<button mat-button>{{ question.answer2 }}</button>
<button mat-raised-button color="accent">
Skip<mat-icon>skip_next</mat-icon>
</button>
</mat-card-actions>
</mat-card>
</ng-container>
</mat-card>
然后在“跳过”和“下一步”按钮上添加点击处理程序,以在每次点击时递增或递减 currentQuestionNumber
。
目前你的代码“有效”,因为你正在将你的 observable 传递给异步管道处理程序,该处理程序会一直执行 ngFor,直到 observable 被解析。
我会更改您的代码,以便您订阅 observable 并处理随后的结果。实际上,我会先转换为承诺并等待它,因为在我看来,这种风格更具可读性和可预测性,尤其是对于“一劳永逸”的事件。
所以像这样更改您的组件(注意:为了简洁起见,我省略了导入和装饰器):
export class PlayComponent implements OnInit {
user_id: Pick<User, "id"> | undefined;
unanswered_questions: Question[];
question$: Observable<Question> | undefined;
questionIndex = 0;
constructor(
private questionService: QuestionService,
private authService: AuthService
) { }
async ngOnInit(): Promise<void> {
this.user_id = this.authService.userId;
await this.unanswered_questions = this.getUnansweredQuestions(this.user_id).toPromise();
}
getUnansweredQuestions(user_id: Pick<User, "id"> | undefined): Observable<Question[]> {
return this.questionService.fetchAllUnansweredQuestions(user_id);
}
skipQuestion(): void {
if (this.questionIndex !== this.getUnansweredQuestions.length) {
this.questionIndex++;
}
}
}
然后是你的 HTML:
<mat-card class="question-card" *ngIf="unanswered_questions">
<mat-card-header>
<div mat-card-avatar class="example-header-image"></div>
<mat-card-title>{{unanswered_questions[questionIndex].title}}</mat-card-title>
</mat-card-header>
<mat-card-content>
<h3>{{unanswered_questions[questionIndex].body}}</h3>
</mat-card-content>
<mat-card-actions>
<button mat-button>{{unanswered_questions[questionIndex].answer1}}</button>
<button mat-button>{{unanswered_questions[questionIndex].answer2}}</button>
<button mat-raised-button color="accent" (click)="skipQuestion()">Skip<mat-icon>skip_next</mat-icon></button>
</mat-card-actions>
</mat-card>
通过将 ngIf 添加到您的 matCard 中,您可以在解析 observable 之前阻止渲染。