Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 6 Scroll Listener Reloads Component

To lay this out as simply as possible, here's my scenario.

1) I have parent component that has a ViewContainerRef to dynamically load in a component within the parent. For my use case, the parents is an empty holder page that replaces itself dynamically with another page dependent on a set of variables.

<ng-template #dynamic></ng-template>

2) The child component has a horizontal scroll div that looks similar to the following:

<div id="carousel" (scroll)="onScroll($event)"> <!-- List of components --> </div>

Any time it is scrolled WITH the (scroll) listener, it reloads the parent component and therefore the scroll position always bounces back to 0 because it was reloaded.

However, if I remove the (scroll) listener the div scrolls without an issue. The problem is, I want to dynamically change items on the page based on the horizontal scroll position.

Does anyone have any thoughts on issues that could arise with embedded components and a scroll listener? Would be GREATLY appreciated!

like image 722
Brayden Avatar asked Aug 10 '18 01:08

Brayden


2 Answers

I suspect that the onScroll is triggering Angular's change detector (like the comments suggest), which for some reason decides the page is dirty -- which triggers a redraw of the page. If that is the case, I suspect the redraw resets the carousel div.

To confirm this suspicion you can change the ChangeDetectionStrategy on your troublesome component. ChangeDetectionStrategy.OnPush will only redraw your component if the data bound to an @Input() (like data bellow) changes OR if you explicitly tell it too.

@Component({
  selector: 'app-neat',
  templateUrl: './neat.component.html',
  // Add this line to your component
  changeDetection: ChangeDetectionStrategy.OnPush 
})
export class NeatComponent {
  @Input() data: string[];
}

That means that when you do want the component to redraw you need to explicitly tell Angular to do so. You can do that like so:

@Component({
  selector: 'app-neat',
  templateUrl: './neat.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {
  @Input() data: string[];

  // Inject the ChangeDetectorRef into your component
  constructor(private cd: ChangeDetectorRef) {}

  refresh() {
    // Manually tell Angular to detect changes and redraw the screen
    this.cd.detectChanges();
  }
}

You can find more info here: https://alligator.io/angular/change-detection-strategy/

This should allow you to have fine grained control over what content on your page redraws when the scroll event is triggered.

If you post more code, we might be able to provide a more specific answer.

like image 100
Pearman Avatar answered Nov 02 '22 03:11

Pearman


I don't know if you are injecting components like this but this is my try to take this problem.

I used renderer to listen to window event scroll in child component.

StackBlitz

Don't mind my styling

like image 39
karoluS Avatar answered Nov 02 '22 02:11

karoluS