ReplaySubject当新对象被添加到Angular时,它不会更新数组



我正在处理一个错误,当我尝试创建新的page对象时,它发送到后端,但它没有更新数组,我需要重新加载页面以查看所有数组。

我在前端的async中使用Observable。我试图console.logpage.component.tsngOnInit,但当我添加新页面并导航到页面时,ngOnInit没有调用。

在创建新页面时发生如下情况。它把我送到pages的路线,在那里我显示了所有的页面列表。但是当我创建新的Page,它返回一个错误说。ERROR Error: Error trying to diff 'Here is the name of the object'. Only arrays and iterables are allowed.

更新:正如Marco所说,这是因为我将页面混合为对象,而不是迭代数组但是我无法解决这个问题,我需要你的帮助。在pageModelpage.service.ts中,当我添加新对象时,它只返回添加的Object而不是整个数组,并且存在我认为的问题,但我不知道如何修复。但是如果我重新加载页面,我可以看到所有的数组。

这是我更新的代码。

这是我的代码。

export class PagesService {
public baseUrl = environment.backend;
private data = new ReplaySubject<any>();
public userID = this.authService.userID;
public editDataDetails: any = [];
public subject = new Subject<any>();
private messageSource = new BehaviorSubject(this.editDataDetails);
getPageID = this.messageSource.asObservable();
constructor(private http: HttpClient, private authService: AuthService) { }
public getPages() {
return this.http.get<any>(`${this.baseUrl}/pages/${this.userID}`).subscribe(res => this.data.next(res));
}
public pageModel(): Observable<Page[]> {
return this.data.asObservable(); // Here it throws error
}
public getPage(id): Observable<any> {
return this.http.get(`${this.baseUrl}/page/${id}`);
}
public setPage(page: Page, id: string) {
const api = `${this.baseUrl}/page`;
const user_id = id;
this.http.post<any>(api, page, {
headers: { user_id }
}).subscribe(res => this.data.next(res));
}
changeMessage(message: string) {
this.messageSource.next(message)
}
public updateDate(id: string, page: Page) {
const api = `${this.baseUrl}/page/${id}`;
return this.http.put<any>(api, page).subscribe(res => this.data.next(res.data));
}

从答案中更新代码。

public updateDate(id: string, page: Page) {
const api = `${this.baseUrl}/page/${id}`;
return this.http.put<any>(api, page).subscribe(res => {
this.lastSetOfData = res;
this.data.next(this.lastSetOfData);
});
}    
}


export class Page {
_id = "";
name = "";
slogan = "";
description = "";
url = "";
telephone: number;
pageUrl: string;
website: string;
founded: number;
organization: number;
email: string;
coverImage: string;
profileImage: string;
specialty?: Specialty[];
branches: Branches[];
locations?: Location[];
phone?:Phone;
userRole?: string;
roles?: Roles[];
}
export class Roles {
role= "";
userID = "";
}

这是page.component的HTML。

<div class="main" *ngIf="!showWeb">
<div *ngFor="let page of pages$ | async" class="card width-900">
<app-pages-list class="d-flex width-900" [page]="page" [details]="'details'"></app-pages-list>
</div>
<div>
</div>
</div>

这是TS文件。

public pages$: Observable<Page[]>;
ngOnInit(): void {    
this.pageService.getPages();
this.pages$ = this.pageService.pageModel();
}

这是我创建新页面时的代码

export class CreatePageComponent implements OnInit {
public page = new Page();
search;
public branch = [];
constructor(public router: Router,
public branchesService: BranchesService,
public authService: AuthService,
public pageService: PagesService,
public shareData: SenderService) { }
ngOnInit(): void {
}
createPage() {
this.page.url = this.page.name;
this.page.branches = this.branch;
this.page.locations = [];
this.page.specialty = [];
this.page.roles = [];
this.page.phone = this.page.phone;
this.page.pageUrl = `${this.page.name.replace(/s/g, "")}${"-Page"}${Math.floor(Math.random() * 1000000000)}`;
this.pageService.setPage(this.page, this.authService.userID);
}
addBranch(event) {
this.branch.push(event);
this.search = "";
}
removeBranch(index) {
this.branch.splice(index, 1);
}
}

从我对你的代码的理解,你的错误被抛出,因为data变量持有2种类型的对象。

PagesServices:

  • getPages中你给data一个Page的列表。
  • setPageupdatePage你给data一个Page的实例。
private data = new ReplaySubject<any>();

当你创建一个新的页面时,data保存你最后创建的页面(不是一个数组)。然后尝试迭代此页面。

<div *ngFor="let page of pages$ | async"

这个错误来自于不能迭代Page对象的事实。您应该停止使用any,以便这种类型的错误在编译时发生,而不是在运行时发生。您还需要存储page数组的一个实例,在您的数组中添加条目,然后重播整个数组。

代码
public updateDate(id: string, page: Page) {
const api = `${this.baseUrl}/page/${id}`;
return this.http.put<any>(api, page).subscribe((res) => {   
const index: number = lastSetOfData.findIndex((_page: Page) => _page._id === res._id);
lastSetOfData[index] = res;
lastSetOfData = [...lastSetOfData];
this.data.next(lastSetOfData);
});
}

updateDate函数也应命名为updatePage

这个问题是@Marco回复中发现的。我将从这里开始详细阐述。

有几种方法可以解决这个问题。可能最快的方法是将实例变量lastSetOfData添加到PagesService中,其中保存了数组的最后一个版本。然后在getPages方法中初始化lastSetOfData。最后,在setPage方法中,您更新lastSetOfData,并在lastSetOfData的末尾添加服务返回的页面,并使用ReplaySubject通知它。

代码可以是这样的

export class PagesService {
public baseUrl = environment.backend;
// specify the type of data notified by the ReplaySubject
private data = new ReplaySubject<Array<Page>>();
// define lastSetOfData as an array of Pages
private lastSetOfData: Array<Page> = [];
....
public getPages() {
return this.http.get<any>(`${this.baseUrl}/page/${this.userID}`).subscribe(res => {
// res should be an array of Pages which we use to initialize lastSetOfData
lastSetOfData = res;
this.data.next(lastSetOfData)
});
}
....
public setPage(page: Page, id: string) {
const api = `${this.baseUrl}/page`;
const user_id = id;
this.http.post<any>(api, page, {
headers: { user_id }
}).subscribe(res => {
// update lastSetOfData appending resp, which should be a Page 
// not the use of the spread operator ... to create a new Array
lastSetOfData = [...lastSetOfData, resp];
// now you notify lastSetOfData
this.data.next(lastSetOfData)
});
}
// probably you have to modify in a similar way also the method updateTable
public updateDate(id: string, page: Page) {
....
}
....
....
}

考虑这可能是解决问题的最快方法。检查它是否有效,然后您可能想要尝试重构代码以寻找更符合常规的解决方案。但我的建议是先看看这是否能解决问题。

问题是你在你的replaysubject中放置了一个对象,尽管数组应该在其他地方。

next(myarray)
next(myobject)

这不会神奇地将一个对象追加到数组中。

要做到这一点,您需要这样做:

data.pipe(take(1)).subscribe(list => {
list.push(newvalue);
data.next(list);
});

基本上就是取最后一个值,a作为新项,然后压入新列表。

最新更新