Мы недавно перевели наши прокручиваемые списки на CDK Virtual Scroller. (Угловой 7.2.12 с угловой / CDK 7.3.7)
Короче говоря, похоже, что VirtualScrollViewport
- это утилизация экземпляров компонентов, а не только шаблона, как предполагает документация.
Live MCVE на StackBlitz (обновлено, чтобы отразить РЕДАКТИРОВАТЬ 1).
РЕДАКТИРОВАТЬ 1
Коллега напомнил мне, что теперь мы используем именованные ссылки вместо ViewChildren()
, например:
HelloComponent
(внутри *cdkVirtualFor
):
@Component({
selector: 'hello',
template: `<h1 [class.active]="active">Data Item {{item}} !</h1>`,
styles: [`.active {background-color: red; color: white}`]
})
export class HelloComponent {
@Input() item: any;
active: boolean = false;
toggle = () => this.active = !this.active;
}
И реализовать его в приложении, например:
<cdk-virtual-scroll-viewport itemSize="75">
<ng-container *cdkVirtualFor="let item of data" templateCacheSize=0>
<hello #hi [item]="item" (click)="clickByReference(hi)"></hello>
</ng-container>
</cdk-virtual-scroll-viewport>
// Non-essentials hidden, see StackBlitz
export class AppComponent {
data = Array.from(Array(100).keys())
clickByReference = (element: any): void => element.toggle();
}
Он изменит цвет фона элемента, на который нажали, на красный, но при прокрутке другие (предположительно те, которые соответствуют некоторому кешированному индексу?) Уже будут красными! Активация одного из них также очистит оригинал.
Источник предполагает , что templateCacheSize
может помочь, но это не так.
Оригинал
Область с возможностью прокрутки содержит компоненты, на которые мы получаем ссылку с @ViewChildren()
и QueryList
, и мы отслеживаем, на кого мы воздействуем, используя индекс в *ngFor
(теперь *cdkVirtualFor
), например так:
<cdk-virtual-scroll-viewport itemSize="75">
<ng-container *cdkVirtualFor="let item of data; let i = index">
<hello #hi
[item]="item"
(click)="click(i)"></hello>
</ng-container>
</cdk-virtual-scroll-viewport>
Затем со страницы общаемся с компонентом в списке:
export class AppComponent {
@ViewChildren('hi') hiRefs: QueryList<HelloComponent>;
data = Array.from(Array(100).keys())
click = (i: number) => this.hiRefs["_results"][i].say(`Hello as ${i}`);
}
Конечно, теперь, когда шаблон отображается в контейнере виртуальной прокрутки, в DOM отображаются только первые n
. Таким образом, если вы прокрутите список ниже того, что было изначально загружено, hiRefs
не содержит ссылку на элемент с соответствующим индексом, выбрасывая ReferenceError
для предоставленного ["_results"][i]
.
Я экспериментировал с trackBy
, но ничего полезного не получил.
РЕДАКТИРОВАТЬ : коллега также попытался передать именованную ссылку, что, как ни странно, вызывает ту же проблему.
Обновление HelloComponent
до
@Component({
selector: 'hello',
template: `<h1 [class.active]="active">Data Item {{item}} !</h1>`,
styles: [`.active {background-color: red}`]
})
export class HelloComponent {
@Input() item: any;
active: boolean;
say = (something: any) => this.active = !this.active;
}
И реализовать его в приложении, например:
<hello #hi [item]="item" (click)="clickByReference(hi)"></hello>
Он изменит цвет фона элемента, по которому щелкнули, на красный, но при прокрутке другие (предположительно, совпадающие с тем же индексом) уже будут красным, , несмотря на то, что @ViewChildren()
* 1069 не используется * вообще!
Кажется, что CDK перерабатывает ссылки на экземпляры компонентов?
Я обновил StackBlitz методом clickByReference()
и переименовал вышеупомянутый в clickByIndex()
.
Как правильно получить ссылку на компонент в списке, чтобы вызывать методы для него?