Skip to content
Advertisement

Is there a way to move to a specific index when an item is added in the Angular?

i have some list and can add/remove item of the list. Is there a way to cause an event to scroll to a specific index (where the item was added) when the item is added? In the current example, the item is added to the front of the list, so the scroll must be moved to the top

for example, when i’m in the middle(or bottom) of the list, if i add item to the list, the scroll move to the top of the list. (or move to some index, this case, index 0).

Tell me how to scroll from parent to child components without changing the structure of the example.

example: https://stackblitz.com/edit/angular-ivy-ymbsj7

Advertisement

Answer

Your problem is that ViewChild wont go into deeper levels when querying, so you cant query for a CdkVirtualScrollViewport in a child elements template. I could solve this with a custom change detection function in your list component.

You should remove this from your your app.ts -> addItem() function:

 // want to move scroll to the top of the list
    this.viewPort.scrollToIndex(0, 'smooth');

and instead create a custom change detection function in your list component, but first move the viewChild of the CdkVirtualScrollViewport to the list component:

 export class ListComponent {
  @ViewChild(CdkVirtualScrollViewport) viewPort: CdkVirtualScrollViewport;
  @Input()
  data: Favorite[];

  @Output()
  removeData = new EventEmitter<Favorite>();

  remove($event) {
    this.removeData.emit($event);
  }

  ngOnChanges(changes: SimpleChanges) {
    if (
      changes.data &&
      changes.data.currentValue &&
      changes.data.previousValue &&
      changes.data.currentValue.length >changes.data.previousValue.length
    ) {
      this.viewPort.scrollToIndex(0, 'smooth');
    }
  }
}

this works perfectly for me. Every time an item is added, it scrolls to the top.

Modified stackblitz link:

https://stackblitz.com/edit/angular-ivy-k5pve6?file=src/app/list/list.component.ts

Another solution(and maybe better) could be passing the ListComponent as a template reference to the addItem() function, then use the compononents viewPort property‘s scroll function.

List Component

...
export class ListComponent {
  @ViewChild(CdkVirtualScrollViewport)
  public viewPort: CdkVirtualScrollViewport;
...
}

AppComponentTemplate with template reference passing of the ListComponent:

<p>Start editing to see some magic happen :)</p>
<input #inputText />
<button #addButton (click)="addItem(list)">Add New</button>
<list-container #list [data]="favoriteList" (removeData)="remove($event)">
</list-container>

AppComponent-> addItem():

 addItem(listComp: ListComponent) {
    const newItem = {
      id: Number(this.input.nativeElement.value) + 1,
      title: `item ${Number(this.input.nativeElement.value) + 1}`,
    };

    this.favoriteList = [newItem, ...this.favoriteList];
    listComp.viewPort.scrollToIndex(0, 'smooth');
  }

StackBlitz for the second solution:

https://stackblitz.com/edit/angular-ivy-ofhubv?file=src/app/app.component.html

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement