Skip to content

Commit 06c3048

Browse files
daem0ndevmhartington
authored andcommitted
fix(angular): route observables available earlier (#17914)
1 parent b47c53d commit 06c3048

File tree

1 file changed

+34
-24
lines changed

1 file changed

+34
-24
lines changed

angular/src/directives/navigation/ion-router-outlet.ts

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -175,18 +175,22 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
175175

176176
const factory = resolver.resolveComponentFactory(component);
177177
const childContexts = this.parentContexts.getOrCreateContext(this.name).children;
178-
const activatedRouteProxy = this.createActivatedRouteProxy(activatedRoute);
178+
179+
// We create an activated route proxy object that will maintain future updates for this component
180+
// over its lifecycle in the stack.
181+
const component$ = new BehaviorSubject<any>(null);
182+
const activatedRouteProxy = this.createActivatedRouteProxy(component$, activatedRoute);
179183

180184
const injector = new OutletInjector(activatedRouteProxy, childContexts, this.location.injector);
181185
cmpRef = this.activated = this.location.createComponent(factory, this.location.length, injector);
182186

187+
// Once the component is created we can push it to our local subject supplied to the proxy
188+
component$.next(cmpRef.instance);
189+
183190
// Calling `markForCheck` to make sure we will run the change detection when the
184191
// `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component.
185192
enteringView = this.stackCtrl.createView(this.activated, activatedRoute);
186193

187-
// Once the component is created, use the component instance to setup observables
188-
this.setupProxyObservables(activatedRouteProxy, cmpRef.instance);
189-
190194
// Store references to the proxy by component
191195
this.proxyMap.set(cmpRef.instance, activatedRouteProxy);
192196
this.currentActivatedRoute$.next({ component: cmpRef.instance, activatedRoute });
@@ -232,43 +236,49 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
232236
}
233237

234238
/**
235-
* Creates a proxy object that we can use to update activated route properties without losing reference
236-
* in the component injector
239+
* Since the activated route can change over the life time of a component in an ion router outlet, we create
240+
* a proxy so that we can update the values over time as a user navigates back to components already in the stack.
237241
*/
238-
private createActivatedRouteProxy(activatedRoute: ActivatedRoute): ActivatedRoute {
242+
private createActivatedRouteProxy(component$: Observable<any>, activatedRoute: ActivatedRoute): ActivatedRoute {
239243
const proxy: any = new ActivatedRoute();
244+
240245
proxy._futureSnapshot = (activatedRoute as any)._futureSnapshot;
241246
proxy._routerState = (activatedRoute as any)._routerState;
242247
proxy.snapshot = activatedRoute.snapshot;
243248
proxy.outlet = activatedRoute.outlet;
244249
proxy.component = activatedRoute.component;
245250

246-
return proxy as ActivatedRoute;
247-
}
251+
// Setup wrappers for the observables so consumers don't have to worry about switching to new observables as the state updates
252+
(proxy as any)._paramMap = this.proxyObservable(component$, 'paramMap');
253+
(proxy as any)._queryParamMap = this.proxyObservable(component$, 'queryParamMap');
254+
proxy.url = this.proxyObservable(component$, 'url');
255+
proxy.params = this.proxyObservable(component$, 'params');
256+
proxy.queryParams = this.proxyObservable(component$, 'queryParams');
257+
proxy.fragment = this.proxyObservable(component$, 'fragment');
258+
proxy.data = this.proxyObservable(component$, 'data');
248259

249-
private setupProxyObservables(proxy: ActivatedRoute, component: any): void {
250-
(proxy as any)._paramMap = this.proxyObservable(component, 'paramMap');
251-
(proxy as any)._queryParamMap = this.proxyObservable(component, 'queryParamMap');
252-
proxy.url = this.proxyObservable(component, 'url');
253-
proxy.params = this.proxyObservable(component, 'params');
254-
proxy.queryParams = this.proxyObservable(component, 'queryParams');
255-
proxy.fragment = this.proxyObservable(component, 'fragment');
256-
proxy.data = this.proxyObservable(component, 'data');
260+
return proxy as ActivatedRoute;
257261
}
258262

259263
/**
260-
* Create a wrapped observable that will switch to the latest activated route matched by the given view id
264+
* Create a wrapped observable that will switch to the latest activated route matched by the given component
261265
*/
262-
private proxyObservable(component: any, path: string): Observable<any> {
263-
return this.currentActivatedRoute$.pipe(
264-
filter(current => current !== null && current.component === component),
265-
switchMap(current => current && (current.activatedRoute as any)[path]),
266-
distinctUntilChanged()
266+
private proxyObservable(component$: Observable<any>, path: string): Observable<any> {
267+
return component$.pipe(
268+
// First wait until the component instance is pushed
269+
filter(component => !!component),
270+
switchMap(component =>
271+
this.currentActivatedRoute$.pipe(
272+
filter(current => current !== null && current.component === component),
273+
switchMap(current => current && (current.activatedRoute as any)[path]),
274+
distinctUntilChanged()
275+
)
276+
)
267277
);
268278
}
269279

270280
/**
271-
* Updates the given proxy route with data from the new incoming route
281+
* Updates the activated route proxy for the given component to the new incoming router state
272282
*/
273283
private updateActivatedRouteProxy(component: any, activatedRoute: ActivatedRoute): void {
274284
const proxy = this.proxyMap.get(component);

0 commit comments

Comments
 (0)