(collection: Iterable<unknown> | undefined | null)
| 479 | * @codeGenApi |
| 480 | */ |
| 481 | export function ɵɵrepeater(collection: Iterable<unknown> | undefined | null): void { |
| 482 | const prevConsumer = setActiveConsumer(null); |
| 483 | const metadataSlotIdx = getSelectedIndex(); |
| 484 | try { |
| 485 | const hostLView = getLView(); |
| 486 | const hostTView = hostLView[TVIEW]; |
| 487 | const metadata = hostLView[metadataSlotIdx] as RepeaterMetadata; |
| 488 | const containerIndex = metadataSlotIdx + 1; |
| 489 | const lContainer = getLContainer(hostLView, containerIndex); |
| 490 | |
| 491 | if (metadata.liveCollection === undefined) { |
| 492 | const itemTemplateTNode = getExistingTNode(hostTView, containerIndex); |
| 493 | metadata.liveCollection = new LiveCollectionLContainerImpl( |
| 494 | lContainer, |
| 495 | hostLView, |
| 496 | itemTemplateTNode, |
| 497 | ); |
| 498 | } else { |
| 499 | metadata.liveCollection.reset(); |
| 500 | } |
| 501 | |
| 502 | const liveCollection = metadata.liveCollection; |
| 503 | reconcile(liveCollection, collection, metadata.trackByFn, prevConsumer); |
| 504 | |
| 505 | // Warn developers about situations where the entire collection was re-created as part of the |
| 506 | // reconciliation pass. Note that this warning might be "overreacting" and report cases where |
| 507 | // the collection re-creation is the intended behavior. Still, the assumption is that most of |
| 508 | // the time it is undesired. |
| 509 | if ( |
| 510 | ngDevMode && |
| 511 | metadata.trackByFn === ɵɵrepeaterTrackByIdentity && |
| 512 | liveCollection.operationsCounter?.wasReCreated(liveCollection.length) && |
| 513 | isViewExpensiveToRecreate(getExistingLViewFromLContainer(lContainer, 0)) |
| 514 | ) { |
| 515 | const message = formatRuntimeError( |
| 516 | RuntimeErrorCode.LOOP_TRACK_RECREATE, |
| 517 | `The configured tracking expression (track by identity) caused re-creation of the entire collection of size ${liveCollection.length}. ` + |
| 518 | 'This is an expensive operation requiring destruction and subsequent creation of DOM nodes, directives, components etc. ' + |
| 519 | 'Please review the "track expression" and make sure that it uniquely identifies items in a collection.', |
| 520 | ); |
| 521 | console.warn(message); |
| 522 | } |
| 523 | |
| 524 | // moves in the container might caused context's index to get out of order, re-adjust if needed |
| 525 | liveCollection.updateIndexes(); |
| 526 | |
| 527 | // handle empty blocks |
| 528 | if (metadata.hasEmptyBlock) { |
| 529 | const bindingIndex = nextBindingIndex(); |
| 530 | const isCollectionEmpty = liveCollection.length === 0; |
| 531 | if (bindingUpdated(hostLView, bindingIndex, isCollectionEmpty)) { |
| 532 | const emptyTemplateIndex = metadataSlotIdx + 2; |
| 533 | const lContainerForEmpty = getLContainer(hostLView, emptyTemplateIndex); |
| 534 | if (isCollectionEmpty) { |
| 535 | const emptyTemplateTNode = getExistingTNode(hostTView, emptyTemplateIndex); |
| 536 | const dehydratedView = findAndReconcileMatchingDehydratedViews( |
| 537 | lContainerForEmpty, |
| 538 | emptyTemplateTNode, |
nothing calls this directly
no test coverage detected
searching dependent graphs…