(
tView: TView,
lView: LView,
templateFn: ComponentTemplate<{}> | null,
context: T,
)
| 188 | */ |
| 189 | |
| 190 | export function refreshView<T>( |
| 191 | tView: TView, |
| 192 | lView: LView, |
| 193 | templateFn: ComponentTemplate<{}> | null, |
| 194 | context: T, |
| 195 | ) { |
| 196 | ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode'); |
| 197 | |
| 198 | if (isDestroyed(lView)) return; |
| 199 | |
| 200 | const flags = lView[FLAGS]; |
| 201 | |
| 202 | // Check no changes mode is a dev only mode used to verify that bindings have not changed |
| 203 | // since they were assigned. We do not want to execute lifecycle hooks in that mode. |
| 204 | const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode(); |
| 205 | const isInExhaustiveCheckNoChangesPass = ngDevMode && isExhaustiveCheckNoChanges(); |
| 206 | |
| 207 | // Start component reactive context |
| 208 | // - We might already be in a reactive context if this is an embedded view of the host. |
| 209 | // - We might be descending into a view that needs a consumer. |
| 210 | enterView(lView); |
| 211 | let returnConsumerToPool = true; |
| 212 | let prevConsumer: ReactiveNode | null = null; |
| 213 | let currentConsumer: ReactiveLViewConsumer | null = null; |
| 214 | if (!isInCheckNoChangesPass) { |
| 215 | if (viewShouldHaveReactiveConsumer(tView)) { |
| 216 | currentConsumer = getOrBorrowReactiveLViewConsumer(lView); |
| 217 | prevConsumer = consumerBeforeComputation(currentConsumer); |
| 218 | } else if (getActiveConsumer() === null) { |
| 219 | // If the current view should not have a reactive consumer but we don't have an active consumer, |
| 220 | // we still need to create a temporary consumer to track any signal reads in this template. |
| 221 | // This is a rare case that can happen with |
| 222 | // - `viewContainerRef.createEmbeddedView(...).detectChanges()`. |
| 223 | // - `viewContainerRef.createEmbeddedView(...)` without any other dirty marking on the parent, |
| 224 | // flagging the parent component for traversal but not triggering a full `refreshView`. |
| 225 | // This temporary consumer marks the first parent that _should_ have a consumer for refresh. |
| 226 | // Once that refresh happens, the signals will be tracked in the parent consumer and we can destroy |
| 227 | // the temporary one. |
| 228 | returnConsumerToPool = false; |
| 229 | currentConsumer = getOrCreateTemporaryConsumer(lView); |
| 230 | prevConsumer = consumerBeforeComputation(currentConsumer); |
| 231 | } else if (lView[REACTIVE_TEMPLATE_CONSUMER]) { |
| 232 | consumerDestroy(lView[REACTIVE_TEMPLATE_CONSUMER]); |
| 233 | lView[REACTIVE_TEMPLATE_CONSUMER] = null; |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | try { |
| 238 | resetPreOrderHookFlags(lView); |
| 239 | |
| 240 | setBindingIndex(tView.bindingStartIndex); |
| 241 | if (templateFn !== null) { |
| 242 | executeTemplate(tView, lView, templateFn, RenderFlags.Update, context); |
| 243 | } |
| 244 | |
| 245 | const hooksInitPhaseCompleted = |
| 246 | (flags & LViewFlags.InitPhaseStateMask) === InitPhaseState.InitPhaseCompleted; |
| 247 |
no test coverage detected