javascript - Subscribing to Observable not triggering change detection - Stack Overflow

I am using 'angular2-virtual-scroll' to implement load on demand. The items used to be driven

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 ponent. 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 ponent 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 ponent 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.

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 ponent. 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 ponent 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 ponent 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.

Share Improve this question edited Feb 23, 2018 at 21:03 Tony_89 asked Feb 23, 2018 at 19:41 Tony_89Tony_89 8171 gold badge15 silver badges40 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 2

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 ponent 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.

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.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745158875a4614289.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信