ReplaySubject 在添加新对象时不会更新数组 Angular

ReplaySubject it is not updating the array when new object is added Angular

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

我在前端的 async 中使用 Observable。 我尝试 console.log ngOnInitpage.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 的列表。
  • setPageupdatePage 中,您给 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);
});

基本上你取最后一个值,一个新项目,然后推送新列表。