title: angular async pipe not updating the view
body: <p>My problem can be best described by analogy with the selectors example of the ngrx documentation to keep things simple (<a href="https://github.com/ngrx/platform/blob/master/docs/store/selectors.md#using-selectors-for-multiple-pieces-of-state" rel="nofollow noreferrer">https://github.com/ngrx/platform/blob/master/docs/store/selectors.md#using-selectors-for-multiple-pieces-of-state</a>).</p>
  
  <p>I use the async pipe to subscribe to certain slices of state which I select using selectors, for instance </p>
  
  <pre><code>this.visibleBooks$ = this.store$.select(selectVisibleBooks)
  </code></pre>
  
  <p>The thing is that, if the <code>allBooks</code> array is "small", &lt;100 items, my view gets updated instantly. But when it is large, >100, my view gets only updated next time change detection is triggered, for instance by scrolling. This is quite a bad user experience, to only see books once you scroll the list. </p>
  
  <p>I looked at the source for async pipe (<a href="https://github.com/angular/angular/blob/master/packages/common/src/pipes/async_pipe.ts" rel="nofollow noreferrer">https://github.com/angular/angular/blob/master/packages/common/src/pipes/async_pipe.ts</a>), and indeed the <code>_updateLatestValue</code> method calls <code>ChangeDetectorRef.markForCheck()</code>, which as far as I understand marks the component to be checked for changes <strong>the next time</strong> change detection is triggered. </p>
  
  <p>My current way around this is by subscribing manually within the top-level component </p>
  
  <pre><code>this.store$.select(selectVisibleBooks).subscribe(cb)
  </code></pre>
  
  <p>and calling <code>ChangeDetectorRef.detectChanges()</code> manually within the callback. </p>
  
  <p>I find this however unsatisfactory and would simply like async pipe to always work, no matter how large the <code>Book[]</code> array. Does anybody have some suggestions or a correction with which I could make things work? </p>
  
  <hr>
  
  <p><strong>edit as per request</strong></p>
  
  <p>The "books store" case above, as said, was just an analogy for the app I'm writing to keep things simple. In reality, my app renders nodes and edges of a graph, where nodes and edges also have a version attached, denoted "vnode", which together with "vedge"s span a version tree. So any graph element has its own version tree. </p>
  
  <p>What I am developing currently is a search form, where we send a certain request to the backend, asking it for any nodes which match a certain set of search key/value pairs. </p>
  
  <p>So, those nodes would then be rendered in a component <code>&lt;nodes-list&gt;</code>, which we pass nodes by input binding</p>
  
  <pre><code>&lt;nodes-list [nodes]="nodes$ | async"&gt;&lt;/nodes-list&gt;
  </code></pre>
  
  <p><code>nodes-list</code> has change detection "on push", while the top-level <code>&lt;search&gt;</code> component has default strategy.</p>
  
  <p><code>nodes$</code> is set within <code>ngOnInit()</code> as </p>
  
  <pre><code>this.nodes$ = this.store$.select(selectFullNodesList)
  </code></pre>
  
  <p><code>selectFullNodesList</code> looks like this:</p>
  
  <pre><code>export const fullNodesSelector = getFullNodesSelector(createSelector(selectSearchState, s =&gt; {
      if (s.currentId) {
          const nodes = s.queries.get(s.currentId).nodes;
          if (nodes) {
              return [...nodes];
          }
      }
      return null;
  }))
  
  export const selectFullNodesList = createSelector(
      fullNodesSelector,
      (global: GlobalState) =&gt; global.data.counts,
      createSelector(selectSearchState, s =&gt; s.sort),
      (nodes, counts, sorting) =&gt; {
          if (!nodes || !counts || !sorting) return null;
          return [...nodes.sort(sorting.sortCbFactory(counts))];
      }
  )
  </code></pre>
  
  <p>Let me explain: </p>
  
  <ul>
  <li><code>getFullNodesSelector(...)</code> I will show below, it sits in a top-level library because we may reuse it in many features. But what it does is, it takes as an argument another selector which points to an array of node &amp; vnode key pairs <code>{key: number, vKey: number}[]</code>, and turns that array into an array of nodes with their vnodes attached (see below how). </li>
  <li>So as you can see, the selector we pass it selects the state of our <code>search</code> feature, if there is a <code>currentId</code>, which is the id of the current request to the backend, then we select the nodes which were the result of our current request.</li>
  <li><code>s.queries</code> is a light wrapper around a Javascript object, which allows me easily get/set values, clone, or add new items to a clone. This I find helpful when working with key/value stores in NGRX. Hence the <code>s.queries.get(s.currentId).nodes</code>. </li>
  <li><code>global.data.counts</code> is simply a list of how many neighbors each node has. This I want to know because I'd like to sort the nodes list by "count". </li>
  <li><code>s.sort</code> is which sorting of the list is currently selected. </li>
  <li>Note the use of <code>sortCbFactory</code>, this factory simply returns the correct callback to pass to <code>Array.sort</code>, but I need <code>counts</code> to be present in the local scope of the callback because otherwise I wouldn't be able to sort by counts. </li>
  <li>So, whenever nodes change (for instance a new version is referenced on the node), counts change (neighbors are added to a node) or sorting changes, the projection function is called, and a new nodes list is emitted. </li>
  <li>Note that we return a fresh array after sorting. </li>
  </ul>
  
  <p><code>selectSearchState</code> is simply a feature selector</p>
  
  <pre><code>export const selectSearchState = createFeatureSelector&lt;SearchState&gt;('search');
  </code></pre>
  
  <p><code>getFullNodesSelector(...)</code> looks like this:</p>
  
  <pre><code>function getFullNodesSelector(keyPairsSelector: MemoizedSelector&lt;object, GraphElementKeyPair[]&gt;): MemoizedSelector&lt;object, INodeJSON&lt;IVNodeJSON&gt;[]&gt; {
      return createSelector(
          keyPairsSelector,
          (s: GlobalState) =&gt; s.data.nodes,
          (s: GlobalState) =&gt; s.data.vnodes,
          (pairs, nodes, vnodes) =&gt; {
              if (!pairs || !nodes || !vnodes) return null;
              return pairs.map(pair =&gt; ({
                  ...nodes.get(pair.key),
                  _SUB: {
                      ...vnodes.get(pair.vKey)
                  }
              }));
          })
  }
  </code></pre>
  
  <p>Some comments again:</p>
  
  <ul>
  <li>As you see, we pass a selector which points to an array of <code>GraphElementKeyPair</code> (<code>{key: number, vKey: number}</code>)</li>
  <li>We ask the global state for the nodes store and vnodes store</li>
  <li>We map all pairs to a fresh object.</li>
  <li>Note that nodes and edges are again the wrapper object mentioned earlier, which has a <code>get</code> method. </li>
  </ul>
  
  <p>Thus, as we've subscribed to <code>this.nodes$</code> with the async pipe, each time there is a new event on the stream <code>&lt;nodes-list&gt;</code> should be updated. However, in practice it appears that this depends on the size of <code>INodeJSON&lt;IVNodeJSON&gt;[]</code>, and that if the array has length > ~80, we've got to trigger change detection manually by clicking somewhere or scrolling. nodes-list is refreshed automatically, as should be the case, for smaller arrays. </p>