订阅 Observable 不触发变化检测

Subscribing to Observable not triggering change detection

我正在使用 'angular2-virtual-scroll' 来实现按需加载。这些项目过去是由 observable 使用由 parent 组件触发的异步管道驱动的。现在我正在尝试从 child 调用我的服务。调用成功,我得到了我的数据,我需要使用订阅事件来应用其他逻辑。问题是当我在订阅函数中更新我的数组时,检测到的更改似乎不起作用。我读过其他类似的问题,但我没有运气找到解决方案。

这是使用服务调用的主要组件。初始请求是从 onInit 完成的。然后,当您向下滚动时,将调用 fetchMore。

import { Component, OnInit, Input, OnDestroy  } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { User } from './../models/user';
import { Role } from './../../roles/models/role';
import { UsersService } from './../services/users.service';
import { ChangeEvent } from 'angular2-virtual-scroll';
import { promise } from 'selenium-webdriver';
import { VirtualScrollComponent } from 'angular2-virtual-scroll';
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'app-users-list',
  template: `
    <div class="status">
        Showing <span class="">{{indices?.start + 1}}</span>
        - <span class="">{{indices?.end}}</span>
        of <span class="">{{users?.length}}</span>
        <span>({{scrollItems?.length}} nodes)</span>
    </div>
    <virtual-scroll [childHeight]="75" [items]="users" (update)="scrollItems = $event" (end)="fetchMore($event)">
        <div #container>
            <app-user-info *ngFor="let user of scrollItems" [roles]="roles" [user]="user">
              <li>
                <a [routerLink]="['/users/edit/', user.id]" class="btn btn-action btn-edit">Edit</a>
              </li>
            </app-user-info>
            <div *ngIf="loading" class="loader">Loading...</div>
        </div>
    </virtual-scroll>
  `
})
export class UsersListComponent implements OnInit, OnDestroy {
  users: User[] = [];
  @Input() roles: Role[];
  currentPage: number;
  scrollItems: User[];
  indices: ChangeEvent;
  readonly bufferSize: number = 20;
  loading: boolean;
  userServiceSub: Subscription;

  constructor(private usersService: UsersService) {
  }

  ngOnInit() {
    this.reset();
  }

  ngOnDestroy() {
      if(this.userServiceSub) {
          this.userServiceSub.unsubscribe();
      }
  }

  reset() {
    this.loading=true;
    this.currentPage = 1;
    this.userServiceSub = this.usersService.getUsers(this.currentPage).subscribe(users => {
        this.users = users;
    });
  }

  fetchMore(event: ChangeEvent) {
    if (event.end !== this.users.length) return;
    this.loading=true;
    this.currentPage += 1;
    this.userServiceSub = this.usersService.getUsers(this.currentPage).subscribe(users => {
        this.users = this.users.concat(users);
    });
  }
}

根据我的阅读,这可能是上下文问题,但我不确定。任何建议都会很棒。

"EDIT"

查看插件组件的源代码,我可以看到捕获更改事件的位置。

VirtualScrollComponent.prototype.ngOnChanges = function (changes) {
    this.previousStart = undefined;
    this.previousEnd = undefined;
    var items = changes.items || {};
    if (changes.items != undefined && items.previousValue == undefined || (items.previousValue != undefined && items.previousValue.length === 0)) {
        this.startupLoop = true;
    }
    this.refresh();
};

如果我在此事件中放置一个断点,它会在初始加载时触发,因此当我们将数组实例化为 [] 时。当我点击页面时它会触发。但是当数组在订阅事件中更新时它不会触发。我什至在其中放置了一个按钮,用于将数组设置为空,并更新视图,因此订阅函数必须破坏更改检测。

所以当你说变化检测似乎不起作用时,我假设你指的是这个:*ngFor="let user of scrollItems"?

我没有使用过那个特定的组件,也没有任何 运行 代码可以使用......但我会先仔细看看这个:

<virtual-scroll [childHeight]="75" 
                [items]="currentBuffer" 
                (update)="scrollItems = $event" 
                (end)="fetchMore($event)">

也许可以更改 (update) 以调用一个方法,以确保它正在发出并且您正在从中得到您期望的结果。

编辑: 这是一个示例订阅,它更新主要绑定 属性 显示我页面的数据:

movies: IMovie[];

getMovies(): void {
    this.movieService.getMovies().subscribe(
        (movies: IMovie[]) => {
            this.movies = movies;
            this.performFilter(null);
        },
        (error: any) => this.errorMessage = <any>error
    );
}

在这种情况下,变化检测工作正常。因此,很可能是其他原因导致了您所看到的问题。

请注意,您的模板 确实 需要绑定到 属性 才能进行更改检测。在我的示例中,我绑定到 movies 属性。在您的示例中,您需要绑定到 users 属性.

所以变化检测没有启动。我必须将 "ChangeDetectorRef" 与函数 "markForCheck" 一起使用才能使更改检测正常工作。我不确定为什么,所以我肯定有一些研究要做。