Subscribing to Observable not triggering change detection

烈酒焚心 提交于 2019-12-11 17:03:27

问题


I am using 'angular2-virtual-scroll' to implement load on demand. The items used to be driven by observable's using the async pipe triggered by the parent component. Now i am trying to call my service from the child. The call is successful and i get my data, i need to use the subscribe event to apply other logic. The issue is change detected does not appear to be working when i update my arrays in the subscribe function. I have read other similar issues but i have had no luck finding a solution.

This is the main component where the service calls are used. The inital request is done from the onInit. And then when you scroll down fetchMore is called.

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

From what i have read this could be a context issue but i am not sure. Any suggestions would be great.

"EDIT"

Looking at the source code for the plugin component i can see where the change event is captured.

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

If i put a breakpoint in this event it fires on the initial load, so when we instantiate the array to []. It fires when i click on the page. But it does not fire when the array is update in the subscribe event. I have even put a button in that sets the array to empty, and that updates the view so the subscribe function must be breaking the change detection.


回答1:


So when you say the change detection does not appear to be working, I assume you are referring to this: *ngFor="let user of scrollItems"?

I have not used that particular component nor do I have any running code to work with ... but I'd start by taking a closer look at this:

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

Maybe change the (update) to call a method just to ensure it is emitting and that you are getting what you expect back from it.

EDIT: Here is an example subscription that updates the primary bound property showing the data for my page:

movies: IMovie[];

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

The change detection works fine in this case. So there is most likely something else going on causing the issue you are seeing.

Note that your template does need to bind to the property for the change detection to work. In my example, I'm binding to the movies property. In your example, you'd need to bind to the users property.




回答2:


So change detection was not firing. I had to use "ChangeDetectorRef" with the function "markForCheck" to get change detection to work correctly. I am not sure why so i definitely have some research to do.



来源:https://stackoverflow.com/questions/48955143/subscribing-to-observable-not-triggering-change-detection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!