订阅 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" 一起使用才能使更改检测正常工作。我不确定为什么,所以我肯定有一些研究要做。
我正在使用 '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" 一起使用才能使更改检测正常工作。我不确定为什么,所以我肯定有一些研究要做。