UNPKG

@angular/cdk

Version:

Angular Material Component Development Kit

157 lines (152 loc) 6.65 kB
import { isObservable, of } from 'rxjs'; import { D as DataSource } from './data-source-d79c6e09.mjs'; import { InjectionToken } from '@angular/core'; /** DataSource wrapper for a native array. */ class ArrayDataSource extends DataSource { _data; constructor(_data) { super(); this._data = _data; } connect() { return isObservable(this._data) ? this._data : of(this._data); } disconnect() { } } /** Indicates how a view was changed by a {@link _ViewRepeater}. */ var _ViewRepeaterOperation; (function (_ViewRepeaterOperation) { /** The content of an existing view was replaced with another item. */ _ViewRepeaterOperation[_ViewRepeaterOperation["REPLACED"] = 0] = "REPLACED"; /** A new view was created with `createEmbeddedView`. */ _ViewRepeaterOperation[_ViewRepeaterOperation["INSERTED"] = 1] = "INSERTED"; /** The position of a view changed, but the content remains the same. */ _ViewRepeaterOperation[_ViewRepeaterOperation["MOVED"] = 2] = "MOVED"; /** A view was detached from the view container. */ _ViewRepeaterOperation[_ViewRepeaterOperation["REMOVED"] = 3] = "REMOVED"; })(_ViewRepeaterOperation || (_ViewRepeaterOperation = {})); /** * Injection token for {@link _ViewRepeater}. This token is for use by Angular Material only. * @docs-private */ const _VIEW_REPEATER_STRATEGY = new InjectionToken('_ViewRepeater'); /** * A repeater that caches views when they are removed from a * {@link ViewContainerRef}. When new items are inserted into the container, * the repeater will reuse one of the cached views instead of creating a new * embedded view. Recycling cached views reduces the quantity of expensive DOM * inserts. * * @template T The type for the embedded view's $implicit property. * @template R The type for the item in each IterableDiffer change record. * @template C The type for the context passed to each embedded view. */ class _RecycleViewRepeaterStrategy { /** * The size of the cache used to store unused views. * Setting the cache size to `0` will disable caching. Defaults to 20 views. */ viewCacheSize = 20; /** * View cache that stores embedded view instances that have been previously stamped out, * but don't are not currently rendered. The view repeater will reuse these views rather than * creating brand new ones. * * TODO(michaeljamesparsons) Investigate whether using a linked list would improve performance. */ _viewCache = []; /** Apply changes to the DOM. */ applyChanges(changes, viewContainerRef, itemContextFactory, itemValueResolver, itemViewChanged) { // Rearrange the views to put them in the right location. changes.forEachOperation((record, adjustedPreviousIndex, currentIndex) => { let view; let operation; if (record.previousIndex == null) { // Item added. const viewArgsFactory = () => itemContextFactory(record, adjustedPreviousIndex, currentIndex); view = this._insertView(viewArgsFactory, currentIndex, viewContainerRef, itemValueResolver(record)); operation = view ? _ViewRepeaterOperation.INSERTED : _ViewRepeaterOperation.REPLACED; } else if (currentIndex == null) { // Item removed. this._detachAndCacheView(adjustedPreviousIndex, viewContainerRef); operation = _ViewRepeaterOperation.REMOVED; } else { // Item moved. view = this._moveView(adjustedPreviousIndex, currentIndex, viewContainerRef, itemValueResolver(record)); operation = _ViewRepeaterOperation.MOVED; } if (itemViewChanged) { itemViewChanged({ context: view?.context, operation, record, }); } }); } detach() { for (const view of this._viewCache) { view.destroy(); } this._viewCache = []; } /** * Inserts a view for a new item, either from the cache or by creating a new * one. Returns `undefined` if the item was inserted into a cached view. */ _insertView(viewArgsFactory, currentIndex, viewContainerRef, value) { const cachedView = this._insertViewFromCache(currentIndex, viewContainerRef); if (cachedView) { cachedView.context.$implicit = value; return undefined; } const viewArgs = viewArgsFactory(); return viewContainerRef.createEmbeddedView(viewArgs.templateRef, viewArgs.context, viewArgs.index); } /** Detaches the view at the given index and inserts into the view cache. */ _detachAndCacheView(index, viewContainerRef) { const detachedView = viewContainerRef.detach(index); this._maybeCacheView(detachedView, viewContainerRef); } /** Moves view at the previous index to the current index. */ _moveView(adjustedPreviousIndex, currentIndex, viewContainerRef, value) { const view = viewContainerRef.get(adjustedPreviousIndex); viewContainerRef.move(view, currentIndex); view.context.$implicit = value; return view; } /** * Cache the given detached view. If the cache is full, the view will be * destroyed. */ _maybeCacheView(view, viewContainerRef) { if (this._viewCache.length < this.viewCacheSize) { this._viewCache.push(view); } else { const index = viewContainerRef.indexOf(view); // The host component could remove views from the container outside of // the view repeater. It's unlikely this will occur, but just in case, // destroy the view on its own, otherwise destroy it through the // container to ensure that all the references are removed. if (index === -1) { view.destroy(); } else { viewContainerRef.remove(index); } } } /** Inserts a recycled view from the cache at the given index. */ _insertViewFromCache(index, viewContainerRef) { const cachedView = this._viewCache.pop(); if (cachedView) { viewContainerRef.insert(cachedView, index); } return cachedView || null; } } export { ArrayDataSource as A, _RecycleViewRepeaterStrategy as _, _ViewRepeaterOperation as a, _VIEW_REPEATER_STRATEGY as b }; //# sourceMappingURL=recycle-view-repeater-strategy-0f32b0a8.mjs.map