【问题标题】:Angular12/rxjs: updating observable data in template and showing changes in templateAngular 12/rxjs:更新模板中的可观察数据并显示模板中的更改
【发布时间】:2021-11-06 08:30:49
【问题描述】:

所以我进行了实时搜索,根据用户输入获取数据。

例子:

export class MyComponent implements OnInit {
      constructor(private httpHandler: HttpHandlerService) { }

      defaultSearchParams: SearchParams = { search: 'bla' }
      searchParams = new BehaviorSubject<SearchParams>(this.defaultSearchParams);
      myData$?: Observable<PageObjects<MyDataObject>>;
    
      ngOnInit(): void {
        this.myData$ = this.searchParams.pipe(
          debounceTime(300),
          switchMap((searchParams: SearchParams) => this.fetchMyData(searchParams)),
        );
      }
    
      fetchMyData(searchParams: SearchParams): Observable<MyDataObject> {
        return this.httpHandler.getMyData(searchParams);
      }
}

我的模板显示数据:

  <div *ngIf="(myData$ | async) as resultset$">
      <div *ngIf="resultset$.elements && resultset$.elements.length">
          <div *ngFor="let dataObject of resultset$.elements">
                ID: {{dataObject.id}}, name {{dataObject.name}}, status {{dataObject.status}}
          </div>
      </div>
  </div>

好的,挑战来了: 在我的模板中,我希望能够更改数据(即新名称、新状态)。

在使用像我这样的可观察对象时,如何在模板中反映这些更改的数据?

期望结果的示例:


  <div *ngIf="(myData$ | async) as resultset$">
      <div *ngIf="resultset$.elements && resultset$.elements.length">
          <div *ngFor="let dataObject of resultset$.elements">
                ID: {{dataObject.id}}, name {{dataObject.name}}, status {{dataObject.status}}
                <button (click)="changeStatus(dataObject)" type="button">Change status</button>
          </div>
      </div>
  </div>
    changeStatus(MyDataObject dataObject) {
         this.httpHandler.changeStatusOfObject(dataObject, 'newStatus')
                .subscribe(newDataObject => //WHERE should I put the newDataObject to, to show the new value in the template???);
    }

【问题讨论】:

  • 什么是myData$.elements
  • elements 是保存实际数据对象集的对象数组
  • 但是myData$是可观察的,这里不能直接访问elements。你应该改用resultset$.elements
  • 啊,对不起,我搞砸了变量名,我会在一秒钟内解决这个问题
  • 在这种情况下,您将获取结果冷存储在外部状态中,例如 BehaviourSubject。每当服务器返回更改时,您就会改变 BehaviourSubject 拥有的内容和next 的结果。 myData$ 将是该 BehaviourSubject 的 Observable

标签: angular typescript rxjs angular12


【解决方案1】:

尝试更改changeStatus函数,将更改推送到预定义的BehaviorSubjectchanges$,与searchParams observable组合形成myData$ observable。

您可以尝试以下方法:

  changes$ = new BehaviorSubject<MyDataObject[]>([]);

  ngOnInit(): void {
    this.myData$ = combineLatest([
      this.searchParams.pipe(
        debounceTime(300),
        switchMap((searchParams: SearchParams) =>
          this.fetchMyData(searchParams)
        )
      ),
      this.changes$,
    ]).pipe(
      map(([data, changes]) => {
        if (changes?.length && data?.elements) {
          changes.forEach((changedItem) => {
            const ndx = data.elements.findIndex(
              (item) => item.id === changedItem.id
            );
            if (ndx !== -1) data.elements[ndx] = changedItem;
          });
        }
        return data;
      })
    );
  }
  changeStatus(dataObject: MyDataObject) {
    this.httpHandler
      .changeStatusOfObject(dataObject, 'newStatus')
      // take one value from this observable and then complete it, to avoid memory leak
      .pipe(take(1))
      .subscribe((newDataObject) => {
        // push the newDataObject to the chagnes$ subject.
        this.changes$.next([newDataObject]);
      });
  }

【讨论】:

  • 不幸的是,这不起作用,changeStatusOfObject 仅返回已更改的单个对象。它也会破坏实时搜索;(
  • 好的,我知道了。我们应该将它们合并在一起。我现在将更新我的答案。
  • 请您现在检查一下。
【解决方案2】:

在我看来,您可以使用BehaviorSubject 来流式传输数据,并在需要更新单个项目时对其进行调整(无需从后端请求数据)。我会这样做:

export class MyComponent implements OnInit {
      constructor(private httpHandler: HttpHandlerService) { }

      defaultSearchParams: SearchParams = { search: 'bla' }
      searchParams = new BehaviorSubject<SearchParams>(this.defaultSearchParams);
      myData$ = new BehaviorSubject<PageObjects<MyDataObject> | null>(null);
    
      ngOnInit(): void {
        this.searchParams.pipe(
          debounceTime(300),
          switchMap((searchParams: SearchParams) => this.fetchMyData(searchParams)),
        ).subscribe(pagedData => myData$.next(pagedData));
      }
    
      fetchMyData(searchParams: SearchParams): Observable<MyDataObject> {
        return this.httpHandler.getMyData(searchParams);
      }

      changeStatus(dataObject: MyDataObject) {
        this.httpHandler
          .changeStatusOfObject(dataObject, 'newStatus')
          .subscribe((newDataObject) => {
            // because now we have a behavior subject, we can get the last emitted value and use it to change just the updated object
            const pagedData = this.myData$.value;
            const elements = [...pagedData.elements];
            const updatedElementIndex = elements.findIndex(e => e.id === newDataObject.id);
            elements[updatedElementIndex] = newDataObject;
            this.myData$.next({
              ...pagedData,
              elements
            });
          });
      }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-25
    • 2022-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-29
    • 2018-07-24
    • 1970-01-01
    相关资源
    最近更新 更多