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