Skip to content

Commit 207d4e9

Browse files
committed
wip: experiments with multi-back navigation
1 parent 6e09583 commit 207d4e9

File tree

10 files changed

+120
-16
lines changed

10 files changed

+120
-16
lines changed

apps/nativescript-demo-ng/src/app/app-routing.module.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ import { ItemsComponent } from './item/items.component';
66
import { ItemDetailComponent } from './item/item-detail.component';
77
// import { HomeComponent } from './home/home.component';
88
// import { BootGuardService } from './boot-guard.service';
9+
import { Nav1Component } from './route-tests';
910

1011
const routes: Routes = [
11-
{ path: '', redirectTo: '/rootlazy', pathMatch: 'full' },
12+
{ path: '', redirectTo: '/nav1', pathMatch: 'full' },
1213
{ path: 'items', component: ItemsComponent },
1314
{ path: 'item/:id', component: ItemDetailComponent },
1415
{ path: 'item2', loadChildren: () => import('./item2/item2.module').then((m) => m.Item2Module) },
1516
{ path: 'rootlazy', loadChildren: () => import('./item3/item3.module').then((m) => m.Item3Module) },
17+
{ path: 'nav1', component: Nav1Component },
18+
{ path: 'nav2', component: Nav1Component },
19+
{ path: 'nav3', component: Nav1Component },
1620

1721
/**
1822
* Test tab named outlets

apps/nativescript-demo-ng/src/app/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { AppComponent } from './app.component';
66
import { ItemsComponent } from './item/items.component';
77
import { ItemDetailComponent } from './item/item-detail.component';
88
import { ModalComponent } from './modal/modal.component';
9+
import { Nav1Component } from './route-tests';
910

1011
/**
1112
* To test tab named outlets, can uncomment imports and declarations
@@ -27,6 +28,7 @@ import { ModalComponent } from './modal/modal.component';
2728
ItemsComponent,
2829
ItemDetailComponent,
2930
ModalComponent,
31+
Nav1Component,
3032
// HomeComponent
3133
],
3234
providers: [],

apps/nativescript-demo-ng/src/app/modal/modal.component.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Component, Inject, OnDestroy, OnInit, Optional, ViewContainerRef } from '@angular/core';
22
import { ModalDialogService, NativeDialogRef, NativeDialogService } from '@nativescript/angular';
33

4+
let vcRef = null;
5+
46
@Component({
57
selector: 'ns-modal',
68
templateUrl: `./modal.component.html`,
@@ -11,10 +13,11 @@ export class ModalComponent implements OnInit, OnDestroy {
1113
constructor(@Optional() private ref: NativeDialogRef<ModalComponent>, private nativeDialog: NativeDialogService, private modalDialog: ModalDialogService, private vcRef: ViewContainerRef) {}
1214

1315
openNewModal() {
14-
this.nativeDialog.open(ModalComponent);
15-
// this.modalDialog.showModal(ModalComponent, {
16-
// viewContainerRef: this.vcRef
17-
// });
16+
vcRef = vcRef || this.vcRef;
17+
// this.nativeDialog.open(ModalComponent);
18+
this.modalDialog.showModal(ModalComponent, {
19+
viewContainerRef: vcRef,
20+
});
1821
}
1922
ngOnInit() {
2023
console.log('modal init');
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Component, inject, OnDestroy } from '@angular/core';
2+
import { ActivatedRoute } from '@angular/router';
3+
import { RouterExtensions } from '@nativescript/angular';
4+
import { Frame } from '@nativescript/core';
5+
6+
let navNumber = 0;
7+
8+
@Component({
9+
template: `
10+
<StackLayout>
11+
<Label [text]="'Nav ' + this.navNumber"></Label>
12+
<Button text="click me" (tap)="navigate()"></Button>
13+
<Button text="Go back twice" (tap)="goBack(4)"></Button>
14+
</StackLayout>
15+
`,
16+
})
17+
export class Nav1Component implements OnDestroy {
18+
router = inject(RouterExtensions);
19+
20+
frame = inject(Frame);
21+
activatedRoute = inject(ActivatedRoute);
22+
navNumber = +this.activatedRoute.snapshot.url.toString()[this.activatedRoute.snapshot.url.toString().length - 1];
23+
24+
constructor() {
25+
// if(navNumber === 0) {
26+
// this.router.router.events.subscribe((evt) => {
27+
// console.log(evt);
28+
// })
29+
// }
30+
// navNumber++;
31+
}
32+
33+
ngOnDestroy() {
34+
const myNavNumber = this.navNumber;
35+
console.log(`nav${myNavNumber} destroy`);
36+
}
37+
38+
navigate() {
39+
const myNavNumber = this.navNumber;
40+
console.log(`nav${myNavNumber} navigate`);
41+
console.log(`/nav${(this.navNumber % 3) + 1}`);
42+
this.router.navigate([`/nav${(this.navNumber % 3) + 1}`]);
43+
}
44+
45+
goBack(times: number) {
46+
// if (this.frame.backStack.length >= times) {
47+
// const entry = this.frame.backStack[this.frame.backStack.length - times];
48+
// this.frame.goBack(entry);
49+
// }
50+
this.router.back({
51+
numberOfBackNavigations: times,
52+
});
53+
}
54+
}

apps/nativescript-demo-ng/src/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { Trace } from '@nativescript/core';
33

44
import { AppModule } from './app/app.module';
55

6-
Trace.enable();
7-
Trace.setCategories('ns-route-reuse-strategy,ns-router');
6+
// Trace.enable();
7+
// Trace.setCategories('ns-route-reuse-strategy,ns-router');
88

99
runNativeScriptAngularApp({
1010
appModuleBootstrap: () =>

packages/angular/src/lib/legacy/directives/dialogs.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ export class ModalDialogService {
8282
// _ngDialogRoot is the first child of the previously detached proxy.
8383
// It should have 'viewController' (iOS) or '_dialogFragment' (Android) available for
8484
// presenting future modal views.
85-
if (parentView._ngDialogRoot) {
86-
parentView = parentView._ngDialogRoot;
85+
while (parentView._modal || parentView._ngDialogRoot) {
86+
parentView = parentView._modal || parentView._ngDialogRoot;
8787
}
8888

8989
// resolve from particular module (moduleRef)
@@ -176,8 +176,8 @@ export class ModalDialogService {
176176
(<ComponentRef<any>>componentViewRef.ref).instance[key] = options.context[key];
177177
}
178178
}
179-
if (componentViewRef !== componentRef.location.nativeElement) {
180-
componentRef.location.nativeElement._ngDialogRoot = componentViewRef.firstNativeLikeView;
179+
if (componentViewRef.firstNativeLikeView !== componentViewRef.view) {
180+
(componentViewRef.view as any)._ngDialogRoot = componentViewRef.firstNativeLikeView;
181181
}
182182
// if we don't detach the view from its parent, ios gets mad
183183
componentViewRef.detachNativeLikeView();

packages/angular/src/lib/legacy/router/ns-location-strategy.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ export class NSLocationStrategy extends LocationStrategy {
161161
throw new Error('NSLocationStrategy.forward() - not implemented');
162162
}
163163

164-
back(outlet?: Outlet, frame?: Frame): void {
164+
back(outlet?: Outlet, frame?: Frame, times = 1): void {
165165
this.currentOutlet = outlet || this.currentOutlet;
166166

167167
if (this.currentOutlet.isPageNavigationBack) {
@@ -202,7 +202,23 @@ export class NSLocationStrategy extends LocationStrategy {
202202

203203
const frameToBack: Frame = this.currentOutlet.getFrameToBack();
204204
if (frameToBack) {
205-
frameToBack.goBack();
205+
if (times > frameToBack.backStack.length) {
206+
times = frameToBack.backStack.length;
207+
}
208+
if (times > 1 && frameToBack.backStack.length >= times) {
209+
this.currentOutlet.navigatingBackTimes = times;
210+
console.log('going back', times);
211+
const entry = frameToBack.backStack[frameToBack.backStack.length - times];
212+
// const statesToPop = this.currentOutlet.states.slice(-(times - 1), -1);
213+
console.log(this.currentOutlet.states.length);
214+
this.currentOutlet.states = [...this.currentOutlet.states.slice(0, -times), this.currentOutlet.states[this.currentOutlet.states.length - 1]];
215+
console.log(this.currentOutlet.states.length);
216+
frameToBack.goBack(entry);
217+
// statesToPop.forEach((state) => this.)
218+
} else {
219+
this.currentOutlet.navigatingBackTimes = 1;
220+
frameToBack.goBack();
221+
}
206222
}
207223
} else {
208224
// Nested navigation - just pop the state

packages/angular/src/lib/legacy/router/ns-location-utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export class Outlet {
2121
modalNavigationDepth: number;
2222
parent: Outlet;
2323
_navigatingBackOutlets = new Set<string>();
24+
navigatingBackTimes = 1;
2425
get isPageNavigationBack() {
2526
return this._navigatingBackOutlets.size > 0;
2627
}

packages/angular/src/lib/legacy/router/ns-route-reuse-strategy.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ class DetachedStateCache {
3737
return this.cache[this.cache.length - 1];
3838
}
3939

40+
public has(key: string): boolean {
41+
return !!this.cache.find((cacheItem) => cacheItem.key === key);
42+
}
43+
4044
public clear() {
4145
if (NativeScriptDebug.isLogEnabled()) {
4246
NativeScriptDebug.routeReuseStrategyLog(`DetachedStateCache.clear() ${this.cache.length} items will be destroyed`);
@@ -159,7 +163,9 @@ export class NSRouteReuseStrategy implements RouteReuseStrategy {
159163

160164
const key = getSnapshotKey(route);
161165
const isBack = outlet ? outlet.isPageNavigationBack : false;
162-
const shouldAttach = isBack && cache.peek()?.key === key;
166+
// instead of checking if the last cache item is this, we check if the key exists
167+
// if exists, it means we're going back multiple times, so we should attach
168+
const shouldAttach = isBack && cache.has(key);
163169

164170
if (NativeScriptDebug.isLogEnabled()) {
165171
NativeScriptDebug.routeReuseStrategyLog(`shouldAttach isBack: ${isBack} key: ${key} result: ${shouldAttach}`);
@@ -217,9 +223,26 @@ export class NSRouteReuseStrategy implements RouteReuseStrategy {
217223

218224
const key = getSnapshotKey(route);
219225
const isBack = outlet ? outlet.isPageNavigationBack : false;
220-
const cachedItem = cache.peek();
221226

222227
let state = null;
228+
let cachedItem = null;
229+
let backTimes = 1;
230+
if (isBack && cache.has(key)) {
231+
console.log('looking for', key);
232+
// eslint-disable-next-line no-cond-assign
233+
while ((cachedItem = cache.peek())) {
234+
console.log(cachedItem.key);
235+
if (cachedItem.key === key && backTimes >= outlet.navigatingBackTimes) {
236+
console.log('found', key);
237+
outlet.navigatingBackTimes = 1;
238+
break;
239+
}
240+
backTimes++;
241+
const oldItem = cache.pop();
242+
destroyComponentRef((oldItem.state as any)?.componentRef);
243+
}
244+
}
245+
// const cachedItem = cache.peek();
223246
if (isBack && cachedItem && cachedItem.key === key) {
224247
state = cachedItem.state;
225248
}

packages/angular/src/lib/legacy/router/router-extensions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type ExtendedNavigationExtras = NavigationExtras & NavigationOptions;
1111
export interface BackNavigationOptions {
1212
outlets?: Array<string>;
1313
relativeTo?: ActivatedRoute | null;
14+
numberOfBackNavigations?: number;
1415
}
1516

1617
@Injectable({
@@ -80,7 +81,7 @@ export class RouterExtensions {
8081
if (outletToBack.isPageNavigationBack) {
8182
NativeScriptDebug.routerError('Attempted to call startGoBack while going back:');
8283
} else {
83-
this.locationStrategy.back(outletToBack);
84+
this.locationStrategy.back(outletToBack, null, options.numberOfBackNavigations || 1);
8485
}
8586
});
8687
}

0 commit comments

Comments
 (0)