CRUD使用observables而不刷新页面



我正在尝试使用Observable在angular中实现CRUD,而不在ts文件中订阅它们,而是在html中使用async

我的目标是获取、添加、编辑和删除从服务器获取的项目,而无需在每次请求后刷新页面。

我试着用BehaviorSubjectReplaySubjectAsyncSubject来做这件事,也在寻找材料,但我没有发现任何有用的东西。

有人能举一个例子来说明如何用尽可能好的模式来实现这种crud吗?

下面我粘贴了从我以前的尝试中清除的代码和从API返回的数据结构。

提前谢谢。

documents.service.ts

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class DocumentsService {
constructor(private http: HttpClient) { }
getDocuments(): Observable<any[]> {
return this.http.get<any[]>(`https://localhost:5001/docs`)
}
postDocument(item: any): Observable<any> {
return this.http.post<any[]>(`https://localhost:5001/docs`, item)
}
putDocument(id: number, item: any): Observable<any> {
return this.http.put<any[]>(`https://localhost:5001/docs/${id}`, item)
}
deleteDocument(id: number): Observable<any> {
return this.http.delete<any>(`https://localhost:5001/docs/${id}`)
}
}

documents.component.ts

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';
import { DocumentsService } from 'src/app/services/documents.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent {
documents$: Observable<any> = new Observable()
constructor(private documentsService: DocumentsService) { }

ngOnInit() {
this.getDocuments();
}
getDocuments(): void {
this.documents$ = this.documentsService.getDocuments()
}
postDocument(): void {
this.documentsService.postDocument({
"title": "title",
"description": "lorem ipsum",
"imageUrl": "https://images.pexels.com/photos/2765111/pexels-photo-2765111.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"madeBy": {
"userName": "mike mock",
"email": "mike@mock.com"
}
})
}
putDocument(): void {
this.documentsService.putDocument(4, {
"title": "title",
"description": "lorem ipsum",
"imageUrl": "https://images.pexels.com/photos/2765111/pexels-photo-2765111.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"madeBy": {
"userName": "mike mock",
"email": "mike@mock.com"
}
})
}
deleteDocument(): void {
this.documentsService.deleteDocument(5)
}
}

documents.component.html

<p routerLink="/">home works!</p>
<button (click)="postDocument()">add me</button>
<button (click)="putDocument()">edit me</button>
<button (click)="deleteDocument()">delete me</button>

<p *ngFor="let document of documents$ | async">
{{ document | json }}
</p>

HTTP GET响应:

[
{
"id": 47,
"title": "docker",
"description": "lorem ipsum",
"imageUrl": "https://images.pexels.com/photos/3464632/pexels-photo-3464632.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"madeBy": {
"username": "mike mock",
"email": "mike@mock.com"
}
},
{
"id": 49,
"title": "linux",
"description": "second description",
"imageUrl": "https://images.pexels.com/photos/3900437/pexels-photo-3900437.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"madeBy": {
"username": "mike mock",
"email": "mike@mock.com"
}
}
]

HTTP POST/PUT/DELETE响应:

{
"id": 50,
"title": "some text",
"description": "lorem ipsum",
"imageUrl": "https://images.pexels.com/photos/2765111/pexels-photo-2765111.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"madeBy": {
"username": "mike mock",
"email": "mike@mock.com"
}
}

Observable是惰性的,在订阅之前不会执行。

将您的组件更新为:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Observable, BehaviorSubject } from 'rxjs';
import { DocumentsService } from 'src/app/services/documents.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent {
documents$: BehaviorSubject<any> = new BehaviorSubject(undefined);
constructor(private documentsService: DocumentsService) { }

ngOnInit() {
this.getDocuments();
}
getDocuments(): void {
this.documentsService.getDocuments().subscribe(this.documents$);
}
postDocument(): void {
this.documentsService.postDocument({
"title": "title",
"description": "lorem ipsum",
"imageUrl": "https://images.pexels.com/photos/2765111/pexels-photo-2765111.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"madeBy": {
"userName": "mike mock",
"email": "mike@mock.com"
}
}).subscribe(_ => this.getDocuments());
}
putDocument(): void {
this.documentsService.putDocument(4, {
"title": "title",
"description": "lorem ipsum",
"imageUrl": "https://images.pexels.com/photos/2765111/pexels-photo-2765111.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"madeBy": {
"userName": "mike mock",
"email": "mike@mock.com"
}
}).subscribe(_ => this.getDocuments());
}
deleteDocument(): void {
this.documentsService.deleteDocument(5).subscribe(_ => this.getDocuments());
}
}

我还强烈建议您强烈键入您的api并删除any的使用。

问题出在您的服务中。在您的服务中,getDocuments((只是对后端进行调用。当您在组件中编写this.documents$=this.documentsService.getDocuments((时,它将调用该函数一次,读取数据,以后再也不会更新它。

因此,您需要创建一个主题来将数据存储在服务中,通过.asObservable((使其在外部可用,将组件链接到该可观察对象,并在每次http调用后更新主题的内容。

类似这样的东西:

export class DocumentsService {
private _documents$ = new BehaviorSubject<Array<Document>>([]);
public documents$: Observable<Array<Document>>;
constructor(private http: HttpClient) { 
this.documents$ = this._documents$.asObservable()
}
getDocuments(): Observable<any[]> {
this.http.get<any[]>(`https://localhost:5001/docs`).switchmap(
(response) => this._documents$.next(response)
)
}
postDocument(item: any): Observable<any> {
# update _documents$ here
}
putDocument(id: number, item: any): Observable<any> {
# update _documents$ here
}
deleteDocument(id: number): Observable<any> {
# update _documents$ here
}
}

然后在您的组件中,只需更新您定义文档的行

this.documents$ = this.documentsService.documents$

它应该起作用。

最新更新