Skip to content

Commit 22da079

Browse files
committed
feat: hmr cache service along with modal dialog handling
1 parent 4644128 commit 22da079

4 files changed

Lines changed: 703 additions & 6 deletions

File tree

packages/angular/src/lib/cdk/dialog/native-modal-ref.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ export class NativeModalRef {
2929
portalOutlet: NativeScriptDomPortalOutlet;
3030
detachedLoaderRef: ComponentRef<DetachedLoader>;
3131
modalViewRef: NgViewRef<any>;
32+
/**
33+
* The actual NativeScript view passed to `parentView.showModal(...)`.
34+
*
35+
* For component portals this is the stable `targetView` ContentView
36+
* wrapper that owns the Angular host PVC. For template portals it
37+
* remains `modalViewRef.firstNativeLikeView` (the historical
38+
* behavior). Keeping a direct reference avoids walking parent
39+
* chains when programmatically closing the modal.
40+
*/
41+
modalView?: View;
3242

3343
private _closeCallback: () => void;
3444
private _isDismissed = false;
@@ -61,11 +71,18 @@ export class NativeModalRef {
6171
this._closeCallback = once(async () => {
6272
this.stateChanged.next({ state: 'closing' });
6373
if (!this._isDismissed) {
64-
this.modalViewRef.firstNativeLikeView?.closeModal();
74+
// Prefer `modalView` (the actual presented view) over the
75+
// legacy `firstNativeLikeView`. Both paths ultimately reach
76+
// the same `_closeModalCallback` via parent walk, but going
77+
// through the presented view is one hop instead of three and
78+
// works even if the rendered first root has been replaced by
79+
// an HMR `ɵɵreplaceMetadata` cycle.
80+
const closeTarget = this.modalView ?? this.modalViewRef.firstNativeLikeView;
81+
closeTarget?.closeModal();
6582
}
6683
await this.location?._closeModalNavigation();
6784
// this.detachedLoaderRef?.destroy();
68-
if (this.modalViewRef?.firstNativeLikeView.isLoaded) {
85+
if (this.modalViewRef?.firstNativeLikeView?.isLoaded) {
6986
fromEvent(this.modalViewRef.firstNativeLikeView, 'unloaded')
7087
.pipe(take(1))
7188
.subscribe(() => this.stateChanged.next({ state: 'closed' }));
@@ -126,6 +143,15 @@ export class NativeModalRef {
126143
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
127144
this.startModalNavigation();
128145

146+
// `targetView` is a stable ContentView wrapper we own. The Angular
147+
// component's host (a `ProxyViewContainer`) is attached as its
148+
// content via the portal outlet below. We present `targetView`
149+
// itself as the modal — *not* the first rendered template root —
150+
// so that component-level HMR (`ɵɵreplaceMetadata`) can re-render
151+
// into the PVC and the modal automatically displays the new
152+
// content via the wrapper. Presenting the rendered first root
153+
// directly worked for the initial open but left subsequent HMR
154+
// updates rendering into a detached PVC, producing a blank modal.
129155
const targetView = new ContentView();
130156
this.portalOutlet = new NativeScriptDomPortalOutlet(
131157
targetView,
@@ -136,15 +162,21 @@ export class NativeModalRef {
136162
const componentRef = this.portalOutlet.attach(portal);
137163
componentRef.changeDetectorRef.detectChanges();
138164
this.modalViewRef = new NgViewRef(componentRef);
165+
this.modalView = targetView;
139166
if (this.modalViewRef.firstNativeLikeView !== this.modalViewRef.view) {
140167
(<any>this.modalViewRef.view)._ngDialogRoot = this.modalViewRef.firstNativeLikeView;
141168
}
142-
this.modalViewRef.firstNativeLikeView['__ng_modal_id__'] = this._id;
143-
// if we don't detach the view from its parent, ios gets mad
144-
this.modalViewRef.detachNativeLikeView();
169+
// Tag both the wrapper (the actual modal root) and the rendered
170+
// first root so `getClosestDialog`'s parent walk finds the modal
171+
// id regardless of whether it starts from a view inside the
172+
// template or from the wrapper.
173+
targetView['__ng_modal_id__'] = this._id;
174+
if (this.modalViewRef.firstNativeLikeView) {
175+
this.modalViewRef.firstNativeLikeView['__ng_modal_id__'] = this._id;
176+
}
145177

146178
const userOptions = this._config.nativeOptions || {};
147-
this.parentView.showModal(this.modalViewRef.firstNativeLikeView, {
179+
this.parentView.showModal(targetView, {
148180
context: null,
149181
...userOptions,
150182
closeCallback: async () => {

0 commit comments

Comments
 (0)