Angular,列表不会动态加载,使用可观察列表。

huangapple go评论130阅读模式
英文:

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 = &quot;&quot;;
option1: string = &quot;&quot;;
option2: string = &quot;&quot;;
option3: string = &quot;&quot;;
option4: string = &quot;&quot;;
answer: number = 0;
} 

this is the crud service

import { HttpClient } from &#39;@angular/common/http&#39;;
import { Injectable } from &#39;@angular/core&#39;;
import { Router } from &#39;@angular/router&#39;;
import { environment } from &#39;src/environments/environment&#39;;
import { QuestionModel } from &#39;../Models/Question&#39;;
import { Observable } from &#39;rxjs&#39;;
@Injectable({
providedIn: &#39;root&#39;
})
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 + &#39;/Question/AddQuestion/&#39;, body);
}
deleteQuestion(id: number) {
return this.http.delete(this.rootUrl + &#39;/Question/delete?id=&#39; + id);
}
EditQuestion(id: number, body: any) {
return this.http.put(this.rootUrl + &#39;/Question/editQuestion?id=&#39; + id, body);
}
showAQuestion(id: number) {
return this.http.get(this.rootUrl + &#39;/Question/getAQuestion?id=&#39; + id);
}
refreshList(): Observable&lt;QuestionModel[]&gt; {
return this.http.get&lt;QuestionModel[]&gt;(this.rootUrl + &#39;/Question/GetAll&#39;);
}
}

this is admin component

import { Component, OnInit } from &#39;@angular/core&#39;;
import { FormBuilder, FormGroup } from &#39;@angular/forms&#39;;
import { NgToastService } from &#39;ng-angular-popup&#39;;
import { CrudService } from &#39;src/app/Services/crud.service&#39;;
@Component({
selector: &#39;app-admin-dashbord&#39;,
templateUrl: &#39;./admin-dashbord.component.html&#39;,
styleUrls: [&#39;./admin-dashbord.component.css&#39;]
})
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) =&gt; {
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: &#39;Success&#39;, summary: &quot;DELETED&quot;, duration: 2000 })
}
}

html for admin component

&lt;app-navbar&gt;&lt;/app-navbar&gt;
&lt;div *ngIf=&quot;crudService.showPopup&quot;&gt;
&lt;app-add-edit-popup&gt;&lt;/app-add-edit-popup&gt;
&lt;/div&gt;
&lt;div class=&quot;flex-col justify-between p-20 max-w-full h-full&quot;&gt;
&lt;div&gt;
&lt;button
class=&quot;flex justify-center cursor-pointe text-white bg-gray-900 hover:bg-purple-800 border-2 border-white p-2 my-4&quot;
(click)=&quot;showPopupButton()&quot;
&gt;
ADD A QUESTION
&lt;/button&gt;
&lt;/div&gt;
&lt;ng-container *ngFor=&quot;let qn of crudService.list; let i = index&quot;&gt;
&lt;div
class=&quot;flex justify-between w-full border-2 border-white bg-gray-900 text-white&quot;
&gt;
&lt;div class=&quot;p-2 m-2&quot;&gt;
&lt;span class=&quot;flex-end right-0&quot;&gt;{{ i + 1 }}&lt;/span&gt;
&lt;p&gt;{{ qn.questionInWords }}&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;flex p-2 m-2 w-36 bg-blue-500&quot;&gt;
&lt;button
class=&quot;p-2 m-1 border-2 hover:bg-purple-800&quot;
(click)=&quot;callEditQuestion(qn.questionId)&quot;
&gt;
Edit
&lt;/button&gt;
&lt;button
class=&quot;p-2 m-1 border-2 hover:bg-red-800&quot;
(click)=&quot;callDeleteQuestion(qn.questionId)&quot;
&gt;
delete
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;px-10 py-2 text-black&quot;&gt;
&lt;ul&gt;
&lt;li [ngClass]=&quot;{ &#39;bg-green-400 rounded-lg&#39;: qn.answer == 0 }&quot;&gt;
(A) {{ qn.option1 }}
&lt;/li&gt;
&lt;li [ngClass]=&quot;{ &#39;bg-green-400 rounded-lg&#39;: qn.answer == 1 }&quot;&gt;
(B) {{ qn.option2 }}
&lt;/li&gt;
&lt;li [ngClass]=&quot;{ &#39;bg-green-400  rounded-lg&#39;: qn.answer == 2 }&quot;&gt;
(C) {{ qn.option3 }}
&lt;/li&gt;
&lt;li [ngClass]=&quot;{ &#39;bg-green-400  rounded-lg&#39;: qn.answer == 3 }&quot;&gt;
(D) {{ qn.option4 }}
&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;Ans: ({{ (qn.answer + 10).toString(36).toUpperCase() }})&lt;/div&gt;
&lt;/div&gt;
&lt;/ng-container&gt;
&lt;/div&gt;

EDIT:
this is the add-edit comnponent :

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import { Component } from &#39;@angular/core&#39;;
import { FormBuilder, FormGroup } from &#39;@angular/forms&#39;;
import { NgToastService } from &#39;ng-angular-popup&#39;;
import { CrudService } from &#39;src/app/Services/crud.service&#39;;
@Component({
selector: &#39;app-add-edit-popup&#39;,
templateUrl: &#39;./add-edit-popup.component.html&#39;,
styleUrls: [&#39;./add-edit-popup.component.css&#39;]
})
export class AddEditPopupComponent {
constructor(
public crudService: CrudService,
private toast: NgToastService,
private fb: FormBuilder,
) { }
addEditForm!: FormGroup;
inputButton: string = &#39;ADD&#39;;
ngOnInit(): void {
this.addEditForm = this.fb.group({
questionId: 0,
questionInWords: &quot;&quot;,
imageName: &quot;&quot;,
option1: &quot;&quot;,
option2: &quot;&quot;,
option3: &quot;&quot;,
option4: &quot;&quot;,
answer: &quot;&quot;,
});
if (this.crudService.idForEdit) {
this.populateEditForm()
this.inputButton = &#39;UPDATE&#39;
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) =&gt; {
this.addEditForm.reset();
//this.crudService.refreshList();
this.crudService.showPopup = false;
this.toast.info({ detail: &#39;SUCCESS!&#39;, summary: &quot;ADDED&quot;, 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) =&gt; {
this.addEditForm.reset();
//this.crudService.refreshList();
this.crudService.showPopup = false;
this.inputButton = &#39;ADD&#39;
this.toast.info({ detail: &#39;SUCCESS!&#39;, summary: &quot;UPDATED&quot;, duration: 2000 })
}
)
}
}
}
populateEditForm() {
this.crudService.showAQuestion(this.crudService.idForEdit)
.subscribe(
(data: any) =&gt; {
this.crudService.dataForEdit = data;
this.addEditForm.controls[&#39;questionId&#39;].setValue(data.questionId);
this.addEditForm.controls[&#39;questionInWords&#39;].setValue(data.questionInWords);
this.addEditForm.controls[&#39;option1&#39;].setValue(data.option1);
this.addEditForm.controls[&#39;option2&#39;].setValue(data.option2);
this.addEditForm.controls[&#39;option3&#39;].setValue(data.option3);
this.addEditForm.controls[&#39;option4&#39;].setValue(data.option4);
this.addEditForm.controls[&#39;answer&#39;].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&lt;QuestionModel[]&gt;

了解有关RxJS BehaviorSubject的更多信息


export class CrudService {
  // ...
  list: BehaviorSubject&lt;QuestionModel[]&gt; = new BehaviorSubject([]);
  // ...
}

在您的组件中,您可以使用类成员订阅此Behavior Subject,如下所示:

export class AdminDashbordComponent implements OnInit {
  // ...
  list = this.crudService.list.asObservable(); // 类型为Observable&lt;QuestionModel[]&gt;
  // ...
}

当您调用API时,更新您的Behavior Subject

  getallQues() {
    this.crudService.refreshList()
      .subscribe({
        next: (data: any) =&gt; {
          this.crudService.list.next(data);
        },
      })
  }

最后,在您的HTML中获取最新值,您可以使用async管道。

*了解有关Angular的async管道的更多信息。

&lt;ng-container *ngFor=&quot;let qn of list | async; let i = index&quot;&gt;
&lt;/ng-container&gt;
英文:

I would suggest changing the type of list in your CrudService to type BehaviorSubject&lt;QuestionModel[]&gt;.

Read more about the RxJS BehaviorSubject


export class CrudService {
  // ...
  list: BehaviorSubject&lt;QuestionModel[]&gt; = 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&lt;QuestionModel[]&gt;
  // ...
}

When you call the API, update your Behavior Subject

  getallQues() {
    this.crudService.refreshList()
      .subscribe({
        next: (data: any) =&gt; {
          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.

&lt;ng-container *ngFor=&quot;let qn of list | async; let i = index&quot;&gt;
&lt;/ng-container&gt;

答案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(() =&gt; {
// Either call a full refresh from the server or
this.crudService.list = this.crudService.list.filter(q =&gt; q.questionId !== id);
});

You would need to do this each time you call the server for add and edit as well.

答案3

得分: 0

为了获得所需的行为,我建议以下操作:

  1. 将问题列表更改为行为主题,以公开可观察对象。

而不是:

list: QuestionModel[] = [];

我建议:

private questionsListSubject = new BehaviorSubject<QuestionModel[]>([]);
    
get questionsList$(): Observable<QuestionModel[]> {
   return this.questionsListSubject.asObservable();
}
  1. 更改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会获得更新的数据,无需重新加载页面

  1. 在您的管理员组件中包括问题列表可观察对象,如下所示:
addForm!: FormGroup;
editForm!: FormGroup;
questionsList$ = this.crudService.questionsList$;
  1. 在管理员组件中简化getAllQues()方法:
getallQues() {
    this.crudService.refreshList().subscribe()
}

您不再需要在此处更新问题列表,因为在服务中已完成。

  1. 更新您的模板以使用questionsList$可观察对象,如下所示:
<ng-container *ngFor="let qn of (questionsList$ | async); let i = index">

注意:确保在使用CRUD方法的任何地方都订阅,以执行更新问题列表的逻辑。

英文:

To get the desired behavior, I would suggest the following:

  1. Change the questions list into a behavioral subject that exposes an observable.

Instead of:

list: QuestionModel[] = [];

I would have:

private questionsListSubject = new BehaviorSubject&lt;QuestionModel[]&gt;([]);
get questionsList$(): Observable&lt;QuestionModel[]&gt;{
return this.questionsListSubject.asObservable();
}
  1. 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 + &#39;/Question/AddQuestion/&#39;, body).pipe(
          tap(v =&gt; {
            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 + &#39;/Question/delete?id=&#39; + id).pipe(
          tap(_ =&gt; {
            const questionsList = this.questionsListSubject.value;
    
            this.questionsListSubject.next(
                 questionsList.filter(question =&gt; question.id !== id)
            );
          })
       );
      }

      editQuestion(id: number, body: any) {
        return this.http.put(this.rootUrl + &#39;/Question/editQuestion?id=&#39; +id, body).pipe(
          tap(_ =&gt; {
             const updatedQuestions = this.questionsListSubject.value.map(question =&gt; question.id === id ? body : question);
            
            this.questionsListSubject.next(updatedQuestions);
          })
       );
      }

      showAQuestion(id: number) {
        return this.http.get(this.rootUrl + &#39;/Question/getAQuestion?id=&#39; + id);
      }

      refreshList(): Observable&lt;QuestionModel[]&gt; {
        return this.http.get&lt;QuestionModel[]&gt;(this.rootUrl + &#39;/Question/GetAll&#39;).pipe(
          tap(questions =&gt; this.questionsListSubject.next(questions))
      );
      }

This makes sure that upon every CRUD operations, the UI gets updated data without having to reload the page.

  1. Include the questions list observable in your admin component as follows:

    addForm!: FormGroup;
    editForm!: FormGroup;
    questionsList$ = this.crudService.questionsList$;
  1. 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.

  1. Update you template to use the questionsList$ observable as follows:
&lt;ng-container *ngFor=&quot;let qn of (questionsList$ | async); let i = index&quot;&gt;

Note: Make sure you subscribe everywhere you use the crud methods so that the logic to update the questions list is executed.

huangapple
  • 本文由 发表于 2023年3月7日 16:53:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75659773.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定