【问题标题】:Subscribing to Observable not triggering change detection订阅 Observable 不会触发变更检测
【发布时间】:2018-08-03 22:33:57
【问题描述】:

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

这是使用服务调用的主要组件。初始请求是从 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);
    });
  }
}

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

“编辑”

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

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();
};

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

【问题讨论】:

    标签: javascript angular observable angular2-observables angular2-changedetection


    【解决方案1】:

    因此,当您说更改检测似乎不起作用时,我假设您指的是:*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 属性。

    【讨论】:

    • 好主意,但您的事件正在正确触发。我所说的更改检测的意思是当我更新订阅函数中的数组时,我希望视图随后会相应更新。目前它不会更新,除非我点击页面,这就是为什么我认为更改检测没有触发(直到我点击页面)但我可能是错的。我对 Angular 还是很陌生。
    • 你指的是哪个数组?您可能需要提供一个 plunker 或 stackblitz 来演示该问题。
    • “users”数组,我意识到不需要名为“currentbuffer”的数组,所以我相应地编辑了代码。我将设置一个 plunker,以便我可以显示问题。但是从插件的示例中,当您在这种情况下更新数组时,“用户”数组更改检测应该触发更新函数,然后导致视图更新。但由于我将更新包装在订阅函数中,因此不会触发更改检测。
    • 我的所有代码都在订阅中设置了关键数据属性,并且更改检测工作正常。所以我认为还有其他问题。
    • 是的,这绝对是一个奇怪的问题。我已经用插件用于处理数组更改的代码更新了我的问题。当我在订阅函数中更新我的数组时,它不会被击中。
    【解决方案2】:

    所以更改检测没有触发。我必须将“ChangeDetectorRef”与“markForCheck”功能一起使用,才能使变更检测正常工作。我不知道为什么,所以我肯定有一些研究要做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-11
      • 2014-11-01
      • 1970-01-01
      • 2018-10-03
      • 2018-10-26
      • 1970-01-01
      • 2016-10-28
      • 1970-01-01
      相关资源
      最近更新 更多