( rNode: RElement, injector: Injector, isRootView = false, )
| 119 | let _retrieveHydrationInfoImpl: typeof retrieveHydrationInfoImpl = () => null; |
| 120 | |
| 121 | export function retrieveHydrationInfoImpl( |
| 122 | rNode: RElement, |
| 123 | injector: Injector, |
| 124 | isRootView = false, |
| 125 | ): DehydratedView | null { |
| 126 | let nghAttrValue = rNode.getAttribute(NGH_ATTR_NAME); |
| 127 | if (nghAttrValue == null) return null; |
| 128 | |
| 129 | // For cases when a root component also acts as an anchor node for a ViewContainerRef |
| 130 | // (for example, when ViewContainerRef is injected in a root component), there is a need |
| 131 | // to serialize information about the component itself, as well as an LContainer that |
| 132 | // represents this ViewContainerRef. Effectively, we need to serialize 2 pieces of info: |
| 133 | // (1) hydration info for the root component itself and (2) hydration info for the |
| 134 | // ViewContainerRef instance (an LContainer). Each piece of information is included into |
| 135 | // the hydration data (in the TransferState object) separately, thus we end up with 2 ids. |
| 136 | // Since we only have 1 root element, we encode both bits of info into a single string: |
| 137 | // ids are separated by the `|` char (e.g. `10|25`, where `10` is the ngh for a component view |
| 138 | // and 25 is the `ngh` for a root view which holds LContainer). |
| 139 | const [componentViewNgh, rootViewNgh] = nghAttrValue.split('|'); |
| 140 | nghAttrValue = isRootView ? rootViewNgh : componentViewNgh; |
| 141 | if (!nghAttrValue) return null; |
| 142 | |
| 143 | // We've read one of the ngh ids, keep the remaining one, so that |
| 144 | // we can set it back on the DOM element. |
| 145 | const rootNgh = rootViewNgh ? `|${rootViewNgh}` : ''; |
| 146 | const remainingNgh = isRootView ? componentViewNgh : rootNgh; |
| 147 | |
| 148 | let data: SerializedView = {}; |
| 149 | // An element might have an empty `ngh` attribute value (e.g. `<comp ngh="" />`), |
| 150 | // which means that no special annotations are required. Do not attempt to read |
| 151 | // from the TransferState in this case. |
| 152 | if (nghAttrValue !== '') { |
| 153 | const transferState = injector.get(TransferState, null, {optional: true}); |
| 154 | if (transferState !== null) { |
| 155 | const nghData = transferState.get(NGH_DATA_KEY, []); |
| 156 | |
| 157 | // The nghAttrValue is always a number referencing an index |
| 158 | // in the hydration TransferState data. |
| 159 | data = nghData[Number(nghAttrValue)]; |
| 160 | |
| 161 | // If the `ngh` attribute exists and has a non-empty value, |
| 162 | // the hydration info *must* be present in the TransferState. |
| 163 | // If there is no data for some reasons, this is an error. |
| 164 | ngDevMode && assertDefined(data, 'Unable to retrieve hydration info from the TransferState.'); |
| 165 | } |
| 166 | } |
| 167 | const dehydratedView: DehydratedView = { |
| 168 | data, |
| 169 | firstChild: rNode.firstChild ?? null, |
| 170 | }; |
| 171 | |
| 172 | if (isRootView) { |
| 173 | // If there is hydration info present for the root view, it means that there was |
| 174 | // a ViewContainerRef injected in the root component. The root component host element |
| 175 | // acted as an anchor node in this scenario. As a result, the DOM nodes that represent |
| 176 | // embedded views in this ViewContainerRef are located as siblings to the host node, |
| 177 | // i.e. `<app-root /><#VIEW1><#VIEW2>...<!--container-->`. In this case, the current |
| 178 | // node becomes the first child of this root view and the next sibling is the first |
nothing calls this directly
no test coverage detected
searching dependent graphs…