Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maintain scroll position in list when new items get added

Tags:

I have a list of items which I am displaying using *ngFor

<div id="container">
  <div 
      [class.selected]="selectedItem.id == item.id"
      #container 
      *ngFor="let item of items; indexBy: byId">{{item.name}}</div>
</div>

I keep updating the lists array periodically.

this.listService.index((items) => this.items = items)

I have a selectedItem which is used to highlight an item on selection.

When I update the lists, new items can be added above the selected item (mostly) and below the selected item. When that happens the selected item moves away from current view position. I want to adjust the scrollOffset of parent div is such a way the position of items in the list remains at the same view position.

Update:

To do this, I am saving

this.offset; = this.container.scrollHeight - this.container.scrollTop;

and added a line after updating this.items

this.listService.index((items) => {
  this.items = items
  this.container.scrollTop = this.container.scrollHeight - this.offset;
})

this doesnt work but, wrapping this with timeout works exactly how I wanted.

setTimeout(() => {
  this.scrollPosition.restore()
}, 300)

After updating this.items there is a delay in rendering the new dom elements.

How can I get the event that new elements have been added?

like image 788
Gaurav Mukherjee Avatar asked Aug 23 '16 12:08

Gaurav Mukherjee


1 Answers

I think something like this will work for you:

Template

<div id="container" #cont>...

Component

@ViewChild('cont') contEl: any;

thisIsCalledWhenNewItemISAdded() {
   let current = this.contEl.nativeElement.scrollTop;

   // ...Item added

   this.contEl.nativeElement.scrollTop = current;
}

So you use the @ViewChild decorator to get the element in your component. Then you capture the scrollTop before a new item gets added and you set it back once the item is added.

like image 107
Filip Lauc Avatar answered Oct 27 '22 17:10

Filip Lauc