Skip to content

Commit

Permalink
fix(core): handle hydration of root components with injected ViewCont…
Browse files Browse the repository at this point in the history
…ainerRef (#50136)

This commit fixes an issue where a root component with an injected ViewContainerRef (for ex. `inject(ViewContainerRef)`) was triggering a certain code path during hydration which didn't handle this case correctly.

Resolves #50133.

PR Close #50136
  • Loading branch information
AndrewKushnir authored and alxhub committed May 9, 2023
1 parent d0023d9 commit d687967
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 2 deletions.
11 changes: 9 additions & 2 deletions packages/core/src/hydration/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {Injector} from '../di/injector';
import {ViewRef} from '../linker/view_ref';
import {getDocument} from '../render3/interfaces/document';
import {RElement, RNode} from '../render3/interfaces/renderer_dom';
import {isRootView} from '../render3/interfaces/type_checks';
import {HEADER_OFFSET, LView, TVIEW, TViewType} from '../render3/interfaces/view';
import {isLContainer, isRootView} from '../render3/interfaces/type_checks';
import {HEADER_OFFSET, HOST, LView, TVIEW, TViewType} from '../render3/interfaces/view';
import {makeStateKey, TransferState} from '../transfer_state';
import {assertDefined} from '../util/assert';

Expand Down Expand Up @@ -142,6 +142,13 @@ export function getComponentLViewForHydration(viewRef: ViewRef): LView|null {
if (isRootView(lView)) {
lView = lView[HEADER_OFFSET];
}

// If a `ViewContainerRef` was injected in a component class, this resulted
// in an LContainer creation at that location. In this case, the component
// LView is in the LContainer's `HOST` slot.
if (isLContainer(lView)) {
lView = lView[HOST];
}
return lView;
}

Expand Down
30 changes: 30 additions & 0 deletions packages/platform-server/test/hydration_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1523,6 +1523,36 @@ describe('platform-server integration', () => {
verifyAllNodesClaimedForHydration(clientRootNode, exceptions);
verifyClientAndSSRContentsMatch(ssrContents, clientRootNode);
});

it('should allow injecting ViewContainerRef in the root component', async () => {
@Component({
standalone: true,
selector: 'app',
template: `Hello World!`,
})
class SimpleComponent {
private vcRef = inject(ViewContainerRef);
}

const html = await ssr(SimpleComponent);
const ssrContents = getAppContents(html);

expect(ssrContents).toContain(`<app ${NGH_ATTR_NAME}`);

resetTViewsFor(SimpleComponent);

const appRef = await hydrate(html, SimpleComponent);
const compRef = getComponentRef<SimpleComponent>(appRef);
appRef.tick();

const clientRootNode = compRef.location.nativeElement;
verifyAllNodesClaimedForHydration(clientRootNode);

// Replace the trailing comment node (added as a result of the
// `ViewContainerRef` injection) before comparing contents.
const _ssrContents = ssrContents.replace(/<\/app><!--container-->/, '</app>');
verifyClientAndSSRContentsMatch(_ssrContents, clientRootNode);
});
});

describe('<ng-template>', () => {
Expand Down

0 comments on commit d687967

Please sign in to comment.