英文:
Angualr, List is not loading dynamically with observable list
问题
以下是您要翻译的内容:
I am trying to make a quiz app where questions with answers will be given to the admin. The list is not loading dynamically. What I want is after the question is added, the list will show automatically without me manually reloading.
this is question model:
export class QuestionModel {
questionId: number = 0;
questionInWords: string = "";
option1: string = "";
option2: string = "";
option3: string = "";
option4: string = "";
answer: number = 0;
}
this is the CRUD service:
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { environment } from 'src/environments/environment';
import { QuestionModel } from '../Models/Question';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class CrudService {
readonly rootUrl = environment.rootUrl;
idForEdit: number = NaN;
dataForEdit!: any;
list: QuestionModel[] = [];
showPopup: boolean = false;
constructor(private http: HttpClient, private route: Router) { }
addQuestion(body: any) {
return this.http.post(this.rootUrl + '/Question/AddQuestion/', body);
}
deleteQuestion(id: number) {
return this.http.delete(this.rootUrl + '/Question/delete?id=' + id);
}
EditQuestion(id: number, body: any) {
return this http.put(this.rootUrl + '/Question/editQuestion?id=' + id, body);
}
showAQuestion(id: number) {
return this.http.get(this.rootUrl + '/Question/getAQuestion?id=' + id);
}
refreshList(): Observable<QuestionModel[]> {
return this.http.get<QuestionModel[]>(this.rootUrl + '/Question/GetAll');
}
}
这是管理员组件:
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { NgToastService } from 'ng-angular-popup';
import { CrudService } from 'src/app/Services/crud.service';
@Component({
selector: 'app-admin-dashboard',
templateUrl: './admin-dashboard.component.html',
styleUrls: './admin-dashboard.component.css'
})
export class AdminDashboardComponent implements OnInit {
constructor(
public crudService: CrudService,
private toast: NgToastService,
private fb: FormBuilder,
) { }
addForm!: FormGroup;
editForm!: FormGroup;
ngOnInit(): void {
this.getallQues();
}
getallQues() {
this.crudService.refreshList()
.subscribe({
next: (data: any) => {
this.crudService.list = data;
},
})
}
showPopupButton() {
this.crudService.showPopup = true;
}
callEditQuestion(id: number) {
this.crudService.idForEdit = id;
this.showPopupButton();
}
callDeleteQuestion(id: number) {
console.log(id);
this.crudService.deleteQuestion(id).subscribe();
this.toast.success({ detail: 'Success', summary: "DELETED", duration: 2000 });
}
}
HTML部分没有什么需要翻译的内容。如果您有其他问题或需要进一步的帮助,请随时告诉我。
英文:
I am trying to make a quiz app where questions with answerrs will be given to the admin.The list is not loading dynamically.What i want is after the questioin is added the list will show automaticlly without me manually realoding.
this is question model:
export class QuestionModel {
questionId: number = 0;
questionInWords: string = "";
option1: string = "";
option2: string = "";
option3: string = "";
option4: string = "";
answer: number = 0;
}
this is the crud service
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { environment } from 'src/environments/environment';
import { QuestionModel } from '../Models/Question';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class CrudService {
readonly rootUrl = environment.rootUrl;
idForEdit: number = NaN;
dataForEdit!: any;
list: QuestionModel[] = [];
showPopup: boolean = false;
constructor(private http: HttpClient, private route: Router) { }
addQuestion(body: any) {
return this.http.post(this.rootUrl + '/Question/AddQuestion/', body);
}
deleteQuestion(id: number) {
return this.http.delete(this.rootUrl + '/Question/delete?id=' + id);
}
EditQuestion(id: number, body: any) {
return this.http.put(this.rootUrl + '/Question/editQuestion?id=' + id, body);
}
showAQuestion(id: number) {
return this.http.get(this.rootUrl + '/Question/getAQuestion?id=' + id);
}
refreshList(): Observable<QuestionModel[]> {
return this.http.get<QuestionModel[]>(this.rootUrl + '/Question/GetAll');
}
}
this is admin component
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { NgToastService } from 'ng-angular-popup';
import { CrudService } from 'src/app/Services/crud.service';
@Component({
selector: 'app-admin-dashbord',
templateUrl: './admin-dashbord.component.html',
styleUrls: ['./admin-dashbord.component.css']
})
export class AdminDashbordComponent implements OnInit {
constructor(
public crudService: CrudService,
private toast: NgToastService,
private fb: FormBuilder,
) { }
addForm!: FormGroup;
editForm!: FormGroup;
ngOnInit(): void {
this.getallQues();
}
getallQues() {
this.crudService.refreshList()
.subscribe({
next: (data: any) => {
this.crudService.list = data;
},
})
}
showPopupButton() {
this.crudService.showPopup = true;
}
callEditQuestion(id: number) {
this.crudService.idForEdit = id;
this.showPopupButton();
}
callDeleteQuestion(id: number) {
console.log(id);
this.crudService.deleteQuestion(id).subscribe();
this.toast.success({ detail: 'Success', summary: "DELETED", duration: 2000 })
}
}
html for admin component
<app-navbar></app-navbar>
<div *ngIf="crudService.showPopup">
<app-add-edit-popup></app-add-edit-popup>
</div>
<div class="flex-col justify-between p-20 max-w-full h-full">
<div>
<button
class="flex justify-center cursor-pointe text-white bg-gray-900 hover:bg-purple-800 border-2 border-white p-2 my-4"
(click)="showPopupButton()"
>
ADD A QUESTION
</button>
</div>
<ng-container *ngFor="let qn of crudService.list; let i = index">
<div
class="flex justify-between w-full border-2 border-white bg-gray-900 text-white"
>
<div class="p-2 m-2">
<span class="flex-end right-0">{{ i + 1 }}</span>
<p>{{ qn.questionInWords }}</p>
</div>
<div class="flex p-2 m-2 w-36 bg-blue-500">
<button
class="p-2 m-1 border-2 hover:bg-purple-800"
(click)="callEditQuestion(qn.questionId)"
>
Edit
</button>
<button
class="p-2 m-1 border-2 hover:bg-red-800"
(click)="callDeleteQuestion(qn.questionId)"
>
delete
</button>
</div>
</div>
<div class="px-10 py-2 text-black">
<ul>
<li [ngClass]="{ 'bg-green-400 rounded-lg': qn.answer == 0 }">
(A) {{ qn.option1 }}
</li>
<li [ngClass]="{ 'bg-green-400 rounded-lg': qn.answer == 1 }">
(B) {{ qn.option2 }}
</li>
<li [ngClass]="{ 'bg-green-400 rounded-lg': qn.answer == 2 }">
(C) {{ qn.option3 }}
</li>
<li [ngClass]="{ 'bg-green-400 rounded-lg': qn.answer == 3 }">
(D) {{ qn.option4 }}
</li>
</ul>
<div>Ans: ({{ (qn.answer + 10).toString(36).toUpperCase() }})</div>
</div>
</ng-container>
</div>
EDIT:
this is the add-edit comnponent :
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { NgToastService } from 'ng-angular-popup';
import { CrudService } from 'src/app/Services/crud.service';
@Component({
selector: 'app-add-edit-popup',
templateUrl: './add-edit-popup.component.html',
styleUrls: ['./add-edit-popup.component.css']
})
export class AddEditPopupComponent {
constructor(
public crudService: CrudService,
private toast: NgToastService,
private fb: FormBuilder,
) { }
addEditForm!: FormGroup;
inputButton: string = 'ADD';
ngOnInit(): void {
this.addEditForm = this.fb.group({
questionId: 0,
questionInWords: "",
imageName: "",
option1: "",
option2: "",
option3: "",
option4: "",
answer: "",
});
if (this.crudService.idForEdit) {
this.populateEditForm()
this.inputButton = 'UPDATE'
console.log(this.addEditForm.value)
}
}
OnSubmit() {
if (!this.crudService.idForEdit) {
if (this.addEditForm.valid) {
console.log(this.addEditForm.value)
this.crudService.addQuestion(this.addEditForm.value)
.subscribe(
(data: any) => {
this.addEditForm.reset();
//this.crudService.refreshList();
this.crudService.showPopup = false;
this.toast.info({ detail: 'SUCCESS!', summary: "ADDED", duration: 2000 })
})
}
} else {
if (this.addEditForm.valid) {
console.log(this.addEditForm.value)
this.crudService.editQuestion(this.addEditForm.value.questionId, this.addEditForm.value)
.subscribe(
(data: any) => {
this.addEditForm.reset();
//this.crudService.refreshList();
this.crudService.showPopup = false;
this.inputButton = 'ADD'
this.toast.info({ detail: 'SUCCESS!', summary: "UPDATED", duration: 2000 })
}
)
}
}
}
populateEditForm() {
this.crudService.showAQuestion(this.crudService.idForEdit)
.subscribe(
(data: any) => {
this.crudService.dataForEdit = data;
this.addEditForm.controls['questionId'].setValue(data.questionId);
this.addEditForm.controls['questionInWords'].setValue(data.questionInWords);
this.addEditForm.controls['option1'].setValue(data.option1);
this.addEditForm.controls['option2'].setValue(data.option2);
this.addEditForm.controls['option3'].setValue(data.option3);
this.addEditForm.controls['option4'].setValue(data.option4);
this.addEditForm.controls['answer'].setValue(data.answer);
}
)
}
closePopup() {
this.crudService.showPopup = false;
this.crudService.idForEdit = NaN;
}
<!-- end snippet -->
I am using the observer, but it did not work.
答案1
得分: 0
我建议将CrudService
中的list
的类型更改为BehaviorSubject<QuestionModel[]>
。
了解有关RxJS BehaviorSubject
的更多信息
export class CrudService {
// ...
list: BehaviorSubject<QuestionModel[]> = new BehaviorSubject([]);
// ...
}
在您的组件中,您可以使用类成员订阅此Behavior Subject,如下所示:
export class AdminDashbordComponent implements OnInit {
// ...
list = this.crudService.list.asObservable(); // 类型为Observable<QuestionModel[]>
// ...
}
当您调用API时,更新您的Behavior Subject
getallQues() {
this.crudService.refreshList()
.subscribe({
next: (data: any) => {
this.crudService.list.next(data);
},
})
}
最后,在您的HTML中获取最新值,您可以使用async
管道。
*了解有关Angular的async
管道的更多信息。
<ng-container *ngFor="let qn of list | async; let i = index">
</ng-container>
英文:
I would suggest changing the type of list
in your CrudService
to type BehaviorSubject<QuestionModel[]>
.
Read more about the RxJS BehaviorSubject
export class CrudService {
// ...
list: BehaviorSubject<QuestionModel[]> = new BehaviorSubject([]);
// ...
}
In your component, you can use a class member to subscribe to this Behavior Subject as follows:
export class AdminDashbordComponent implements OnInit {
// ...
list = this.crudService.list.asObservable(); // Type Observable<QuestionModel[]>
// ...
}
When you call the API, update your Behavior Subject
getallQues() {
this.crudService.refreshList()
.subscribe({
next: (data: any) => {
this.crudService.list.next(data);
},
})
}
And finally, to get the latest value in your HTML, you can use the async
pipe.
*Read more about Angular's async
pipe.
<ng-container *ngFor="let qn of list | async; let i = index">
</ng-container>
答案2
得分: 0
完成通话后,您需要执行某些操作。
this.crudService.deleteQuestion(id).subscribe(() => {
// 要么从服务器进行完全刷新,要么
this.crudService.list = this.crudService.list.filter(q => q.questionId !== id);
});
每次调用服务器进行添加和编辑时,您都需要执行此操作。
英文:
You have to do something once the call is complete
this.crudService.deleteQuestion(id).subscribe(() => {
// Either call a full refresh from the server or
this.crudService.list = this.crudService.list.filter(q => q.questionId !== id);
});
You would need to do this each time you call the server for add and edit as well.
答案3
得分: 0
为了获得所需的行为,我建议以下操作:
- 将问题列表更改为行为主题,以公开可观察对象。
而不是:
list: QuestionModel[] = [];
我建议:
private questionsListSubject = new BehaviorSubject<QuestionModel[]>([]);
get questionsList$(): Observable<QuestionModel[]> {
return this.questionsListSubject.asObservable();
}
- 更改CRUD操作方法以在每次进行更改时更新您的问题列表,如下所示:
addQuestion(body: any) {
return this.http.post(this.rootUrl + '/Question/AddQuestion/', body).pipe(
tap(v => {
const questionsList = this.questionsListSubject.value;
// 假设您的端点返回已添加的问题
questionsList.push(v);
this.questionsListSubject.next(questionsList);
})
);
}
deleteQuestion(id: number) {
return this.http.delete(this.rootUrl + '/Question/delete?id=' + id).pipe(
tap(_ => {
const questionsList = this.questionsListSubject.value;
this.questionsListSubject.next(
questionsList.filter(question => question.id !== id)
);
})
);
}
editQuestion(id: number, body: any) {
return this.http.put(this.rootUrl + '/Question/editQuestion?id=' + id, body).pipe(
tap(_ => {
const updatedQuestions = this.questionsListSubject.value.map(question => question.id === id ? body : question);
this.questionsListSubject.next(updatedQuestions);
})
);
}
showAQuestion(id: number) {
return this.http.get(this.rootUrl + '/Question/getAQuestion?id=' + id);
}
refreshList(): Observable<QuestionModel[]> {
return this.http.get<QuestionModel[]>(this.rootUrl + '/Question/GetAll').pipe(
tap(questions => this.questionsListSubject.next(questions))
);
}
这确保了在进行每个CRUD操作时,UI会获得更新的数据,无需重新加载页面。
- 在您的管理员组件中包括问题列表可观察对象,如下所示:
addForm!: FormGroup;
editForm!: FormGroup;
questionsList$ = this.crudService.questionsList$;
- 在管理员组件中简化
getAllQues()
方法:
getallQues() {
this.crudService.refreshList().subscribe()
}
您不再需要在此处更新问题列表,因为在服务中已完成。
- 更新您的模板以使用
questionsList$
可观察对象,如下所示:
<ng-container *ngFor="let qn of (questionsList$ | async); let i = index">
注意:确保在使用CRUD方法的任何地方都订阅,以执行更新问题列表的逻辑。
英文:
To get the desired behavior, I would suggest the following:
- Change the questions list into a behavioral subject that exposes an observable.
Instead of:
list: QuestionModel[] = [];
I would have:
private questionsListSubject = new BehaviorSubject<QuestionModel[]>([]);
get questionsList$(): Observable<QuestionModel[]>{
return this.questionsListSubject.asObservable();
}
- Change the crud operations methods to update your questions list every time a change is made as follows:
addQuestion(body: any) {
return this.http.post(this.rootUrl + '/Question/AddQuestion/', body).pipe(
tap(v => {
const questionsList = this.questionsListSubject.value;
// Assuming your endpoint returns the added question
questionsList.push(v);
this.questionsListSubject.next(questionsList);
})
);
}
deleteQuestion(id: number) {
return this.http.delete(this.rootUrl + '/Question/delete?id=' + id).pipe(
tap(_ => {
const questionsList = this.questionsListSubject.value;
this.questionsListSubject.next(
questionsList.filter(question => question.id !== id)
);
})
);
}
editQuestion(id: number, body: any) {
return this.http.put(this.rootUrl + '/Question/editQuestion?id=' +id, body).pipe(
tap(_ => {
const updatedQuestions = this.questionsListSubject.value.map(question => question.id === id ? body : question);
this.questionsListSubject.next(updatedQuestions);
})
);
}
showAQuestion(id: number) {
return this.http.get(this.rootUrl + '/Question/getAQuestion?id=' + id);
}
refreshList(): Observable<QuestionModel[]> {
return this.http.get<QuestionModel[]>(this.rootUrl + '/Question/GetAll').pipe(
tap(questions => this.questionsListSubject.next(questions))
);
}
This makes sure that upon every CRUD operations, the UI gets updated data without having to reload the page.
- Include the questions list observable in your admin component as follows:
addForm!: FormGroup;
editForm!: FormGroup;
questionsList$ = this.crudService.questionsList$;
- Simplify the
getAllQues()
method in admin component to:
getallQues() {
this.crudService.refreshList().subscribe()
}
You no longer need to update the questions list here since it is done in the service.
- Update you template to use the
questionsList$
observable as follows:
<ng-container *ngFor="let qn of (questionsList$ | async); let i = index">
Note: Make sure you subscribe everywhere you use the crud methods so that the logic to update the questions list is executed.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论