ReplaySubject 在添加新对象时不会更新数组 Angular
ReplaySubject it is not updating the array when new object is added Angular
我正在处理一个错误,当我尝试创建新的 page
对象时,它发送到后端但它没有更新数组,我需要重新加载页面才能看到所有数组。
我在前端的 async
中使用 Observable。
我尝试 console.log ngOnInit
的 page.component.ts
但是当我添加新页面并导航到页面时 ngOnInit
它没有调用。
在创建新页面时会发生这种情况。
它会将我发送到 pages
的路线,在那里我会显示所有页面列表。
但是当我创建新的 Page
时,它会返回一个错误提示。
ERROR Error: Error trying to diff 'Here is the name of the object'. Only arrays and iterables are allowed
.
更新:正如 Marco 所说,发生这种情况是因为我将页面混合为对象而不是遍历数组
但我无法解决它,我需要你的帮助。
在 pageModel
处的 page.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
的列表。
- 在
setPage
和 updatePage
中,您给 data
一个 Page
. 的实例
private data = new ReplaySubject<any>();
当您创建新页面时,data
保留您创建的最后一个页面(不是数组)。然后你尝试迭代这个页面。
<div *ngFor="let page of pages$ | async"
此错误是因为您无法迭代 Page
对象。
您应该停止使用 any
以便此类错误发生在编译时,而不是运行时。您还需要存储页面数组的实例,在 post 之后添加数组中的项目,然后重播整个数组。
代码
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) {
....
}
....
....
}
认为这可能是解决问题的最快方法。检查它是否有效,然后您可能想尝试重构代码以寻找更 rx-idiomatic 的解决方案。不过我的建议是先看看能不能解决问题。
问题是你把一个对象放在了你的重播主题中,尽管在其他地方应该是一个数组。
next(myarray)
next(myobject)
这不会神奇地将对象附加到数组。
为此,您需要这样的东西:
data.pipe(take(1)).subscribe(list => {
list.push(newvalue);
data.next(list);
});
基本上你取最后一个值,一个新项目,然后推送新列表。
我正在处理一个错误,当我尝试创建新的 page
对象时,它发送到后端但它没有更新数组,我需要重新加载页面才能看到所有数组。
我在前端的 async
中使用 Observable。
我尝试 console.log ngOnInit
的 page.component.ts
但是当我添加新页面并导航到页面时 ngOnInit
它没有调用。
在创建新页面时会发生这种情况。
它会将我发送到 pages
的路线,在那里我会显示所有页面列表。
但是当我创建新的 Page
时,它会返回一个错误提示。
ERROR Error: Error trying to diff 'Here is the name of the object'. Only arrays and iterables are allowed
.
更新:正如 Marco 所说,发生这种情况是因为我将页面混合为对象而不是遍历数组
但我无法解决它,我需要你的帮助。
在 pageModel
处的 page.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
的列表。 - 在
setPage
和updatePage
中,您给data
一个Page
. 的实例
private data = new ReplaySubject<any>();
当您创建新页面时,data
保留您创建的最后一个页面(不是数组)。然后你尝试迭代这个页面。
<div *ngFor="let page of pages$ | async"
此错误是因为您无法迭代 Page
对象。
您应该停止使用 any
以便此类错误发生在编译时,而不是运行时。您还需要存储页面数组的实例,在 post 之后添加数组中的项目,然后重播整个数组。
代码
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) {
....
}
....
....
}
认为这可能是解决问题的最快方法。检查它是否有效,然后您可能想尝试重构代码以寻找更 rx-idiomatic 的解决方案。不过我的建议是先看看能不能解决问题。
问题是你把一个对象放在了你的重播主题中,尽管在其他地方应该是一个数组。
next(myarray)
next(myobject)
这不会神奇地将对象附加到数组。
为此,您需要这样的东西:
data.pipe(take(1)).subscribe(list => {
list.push(newvalue);
data.next(list);
});
基本上你取最后一个值,一个新项目,然后推送新列表。