title: Obtaining a static component reference within a cdk-virtual-scroller? (References are recycled)
body: <p>We recently transitioned our scrollable lists to CDK Virtual Scroller. (Angular 7.2.12 with angular/cdk 7.3.7)</p>
  
  <p>In short, it seems that the <code>VirtualScrollViewport</code> is recycling component instances, not just the template as the documentation suggests.</p>
  
  <p><a href="https://stackblitz.com/edit/angular-virtual-scrolling-with-component-state" rel="nofollow noreferrer">Live MCVE on StackBlitz</a> (updated to reflect EDIT 1).</p>
  
  <p><strong>EDIT 1</strong></p>
  
  <p>A colleague reminded me that we're now using named references instead of <code>ViewChildren()</code>, like so:</p>
  
  <p><code>HelloComponent</code> (inside the <code>*cdkVirtualFor</code>):</p>
  
  <pre><code>@Component({
    selector: 'hello',
    template: `&lt;h1 [class.active]="active"&gt;Data Item {{item}} !&lt;/h1&gt;`,
    styles: [`.active {background-color: red; color: white}`]
  })
  export class HelloComponent  {
    @Input() item: any;
    active: boolean = false;
    toggle = () =&gt; this.active = !this.active;
  }
  </code></pre>
  
  <p>And implementing it in the App like:</p>
  
  <pre><code>&lt;cdk-virtual-scroll-viewport itemSize="75"&gt;
    &lt;ng-container *cdkVirtualFor="let item of data" templateCacheSize=0&gt;
      &lt;hello #hi [item]="item" (click)="clickByReference(hi)"&gt;&lt;/hello&gt;
    &lt;/ng-container&gt;
  &lt;/cdk-virtual-scroll-viewport&gt;
  
  // Non-essentials hidden, see StackBlitz
  export class AppComponent  {
    data = Array.from(Array(100).keys())
    clickByReference = (element: any): void =&gt; element.toggle();
  }
  </code></pre>
  
  <p>It will change the background colour of the clicked element to red, but when scrolling, others (presumably those that match some cached index?) will already be red! Activating one of those will clear the original as well.</p>
  
  <p><a href="https://github.com/angular/material2/blob/8cfaeea4b0b9bf0f10529a8d50d9afd06014b8a1/src/cdk/scrolling/scrolling.md" rel="nofollow noreferrer">The source suggests</a> that <code>templateCacheSize</code> might help, but it doesn't.</p>
  
  <p><strong>Original</strong></p>
  
  <p>The scrollable area contains components which we get a reference to with a <code>@ViewChildren()</code> and <code>QueryList</code> and we track which one we are acting on using an index in the <code>*ngFor</code> (now <code>*cdkVirtualFor</code>), like so:</p>
  
  <pre><code>&lt;cdk-virtual-scroll-viewport itemSize="75"&gt;
    &lt;ng-container *cdkVirtualFor="let item of data; let i = index"&gt;
      &lt;hello  #hi
              [item]="item"
              (click)="click(i)"&gt;&lt;/hello&gt;
    &lt;/ng-container&gt;
  &lt;/cdk-virtual-scroll-viewport&gt;
  </code></pre>
  
  <p>Then, from the page, we communicate with the component in the list:</p>
  
  <pre><code>export class AppComponent  {
    @ViewChildren('hi') hiRefs: QueryList&lt;HelloComponent&gt;;
    data = Array.from(Array(100).keys())
  
    click = (i: number) =&gt; this.hiRefs["_results"][i].say(`Hello as ${i}`);
  }
  </code></pre>
  
  <p>Of course, now that the template is rendered in a virtual scroll container, only the first <code>n</code> are rendered into the DOM. So if you scroll down the list beyond what is initially loaded, <code>hiRefs</code> does not contain a reference to the item with the corresponding index, throwing a <code>ReferenceError</code> for the provided <code>["_results"][i]</code>.</p>
  
  <p>I experimented with <code>trackBy</code> but didn't get anything fruitful.</p>
  
  <p><strong>EDIT</strong>: A colleague has also attempted to pass a named reference, which curiously has the same problem.</p>
  
  <p>Updating the <code>HelloComponent</code> to</p>
  
  <pre><code>@Component({
    selector: 'hello',
    template: `&lt;h1 [class.active]="active"&gt;Data Item {{item}} !&lt;/h1&gt;`,
    styles: [`.active {background-color: red}`]
  })
  export class HelloComponent  {
    @Input() item: any;
    active: boolean;
  
    say = (something: any) =&gt; this.active = !this.active;
  }
  </code></pre>
  
  <p>And implementing it in the App like:</p>
  
  <pre><code>&lt;hello #hi [item]="item" (click)="clickByReference(hi)"&gt;&lt;/hello&gt;
  </code></pre>
  
  <p>It will change the background colour of the clicked element to red, but when scrolling, others (presumably those that match the same index) will already be red, <em>despite not using the</em> <code>@ViewChildren()</code> <code>QueryList</code> at all!</p>
  
  <p>It seems that the CDK is recycling component instance references?</p>
  
  <p>I updated the StackBlitz with the method <code>clickByReference()</code>, and renamed the one above to <code>clickByIndex()</code>.</p>
  
  <p>How can I correctly get a reference to the component in the list in order to call methods on it?</p>