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