@angular/cdk
Version:
Angular Material Component Development Kit
157 lines (152 loc) • 6.65 kB
JavaScript
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