* Recreates an LView in-place from a new component definition. * @param importMeta `import.meta` information. * @param id HMR ID for the component. * @param newDef Definition from which to recreate the view. * @param oldDef Previous component definition being swapped out. * @param lView View to
( importMeta: ImportMetaExtended | null, id: string | null, newDef: ComponentDef<unknown>, oldDef: ComponentDef<unknown>, lView: LView<unknown>, )
| 225 | * @param lView View to be recreated. |
| 226 | */ |
| 227 | function recreateLView( |
| 228 | importMeta: ImportMetaExtended | null, |
| 229 | id: string | null, |
| 230 | newDef: ComponentDef<unknown>, |
| 231 | oldDef: ComponentDef<unknown>, |
| 232 | lView: LView<unknown>, |
| 233 | ): void { |
| 234 | const instance = lView[CONTEXT]; |
| 235 | let host = lView[HOST]! as HTMLElement; |
| 236 | // In theory the parent can also be an LContainer, but it appears like that's |
| 237 | // only the case for embedded views which we won't be replacing here. |
| 238 | const parentLView = lView[PARENT] as LView; |
| 239 | ngDevMode && assertLView(parentLView); |
| 240 | const tNode = lView[T_HOST] as TElementNode; |
| 241 | ngDevMode && assertTNodeType(tNode, TNodeType.Element); |
| 242 | ngDevMode && assertNotEqual(newDef, oldDef, 'Expected different component definition'); |
| 243 | const zone = lView[INJECTOR].get(NgZone, null); |
| 244 | const recreate = () => { |
| 245 | // If we're recreating a component with shadow DOM encapsulation, it will have attached a |
| 246 | // shadow root. The browser will throw if we attempt to attach another one and there's no way |
| 247 | // to detach it. Our only option is to make a clone only of the root node, replace the node |
| 248 | // with the clone and use it for the newly-created LView. |
| 249 | if ( |
| 250 | oldDef.encapsulation === ViewEncapsulation.ShadowDom || |
| 251 | oldDef.encapsulation === ViewEncapsulation.ExperimentalIsolatedShadowDom |
| 252 | ) { |
| 253 | const newHost = host.cloneNode(false) as HTMLElement; |
| 254 | host.replaceWith(newHost); |
| 255 | host = newHost; |
| 256 | } |
| 257 | |
| 258 | // Recreate the TView since the template might've changed. |
| 259 | const newTView = getOrCreateComponentTView(newDef); |
| 260 | |
| 261 | // Create a new LView from the new TView, but reusing the existing TNode and DOM node. |
| 262 | const newLView = createLView( |
| 263 | parentLView, |
| 264 | newTView, |
| 265 | instance, |
| 266 | getInitialLViewFlagsFromDef(newDef), |
| 267 | host, |
| 268 | tNode, |
| 269 | null, |
| 270 | null, // The renderer will be created a bit further down once the old one is destroyed. |
| 271 | null, |
| 272 | null, |
| 273 | null, |
| 274 | ); |
| 275 | |
| 276 | // Detach the LView from its current place in the tree so we don't |
| 277 | // start traversing any siblings and modifying their structure. |
| 278 | replaceLViewInTree(parentLView, lView, newLView, tNode.index); |
| 279 | |
| 280 | // Destroy the detached LView. |
| 281 | destroyLView(lView[TVIEW], lView); |
| 282 | |
| 283 | // Clean up any dehydrated views left over from SSR hydration. |
| 284 | // Neither destroyLView nor removeViewFromDOM handle DOM nodes |
no test coverage detected
searching dependent graphs…