Skip to content

Commit 221e404

Browse files
authored
fix(router): query params are now preserved when navigating back (#2062)
1 parent b6ac290 commit 221e404

File tree

5 files changed

+80
-16
lines changed

5 files changed

+80
-16
lines changed

Diff for: e2e/router/app/first/first.component.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ import { RouterExtensions } from "@nativescript/angular/router";
33
import { Page } from "@nativescript/core/ui/page";
44

55
import { CounterService } from "../counter.service";
6+
import { ActivatedRoute } from "@angular/router";
7+
import { Subscription } from "rxjs";
68

79
@Component({
810
selector: "first",
911
template: `
1012
<StackLayout>
1113
<Label text="FirstComponent" class="header"></Label>
1214
13-
<Button text="GO TO SECOND" automationText="GO TO SECOND" [nsRouterLink]="['/second','1']"></Button>
15+
<Button text="GO TO SECOND" automationText="GO TO SECOND" [nsRouterLink]="['/second','1']" [queryParams]="{prop: 'xxx'}"></Button>
1416
<Button text="GO TO C-LESS SECOND" automationText="GO TO C-LESS SECOND" [nsRouterLink]="['/c-less', 'deep', '100', 'detail', '200']"></Button>
1517
1618
<Button text="GO TO LAZY HOME" automationText="GO TO LAZY HOME" [nsRouterLink]="['/lazy','home']"></Button>
@@ -26,9 +28,11 @@ import { CounterService } from "../counter.service";
2628
export class FirstComponent implements OnInit, OnDestroy, DoCheck {
2729
public message: string = "";
2830
public doCheckCount: number = 0;
31+
sub: Subscription;
2932

3033
constructor(
3134
private routerExt: RouterExtensions,
35+
private route: ActivatedRoute,
3236
public service: CounterService,
3337
page: Page) {
3438

@@ -37,9 +41,14 @@ export class FirstComponent implements OnInit, OnDestroy, DoCheck {
3741

3842
ngOnInit() {
3943
console.log("FirstComponent - ngOnInit()");
44+
this.sub = this.route.queryParams.subscribe((params) =>{
45+
console.log("FIRST PARAMS:");
46+
console.log(params);
47+
});
4048
}
4149

4250
ngOnDestroy() {
51+
this.sub.unsubscribe();
4352
console.log("FirstComponent - ngOnDestroy()");
4453
}
4554

Diff for: e2e/router/app/second/second.component.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ActivatedRoute } from "@angular/router";
33

44
import { RouterExtensions } from "@nativescript/angular/router";
55
import { Page } from "@nativescript/core/ui/page";
6-
import { Observable } from "rxjs";
6+
import { Observable, Subscription } from "rxjs";
77
import { map } from "rxjs/operators";
88
import { CounterService } from "../counter.service";
99

@@ -36,6 +36,7 @@ import { CounterService } from "../counter.service";
3636
export class SecondComponent implements OnInit, OnDestroy {
3737
public depth$: Observable<string>;
3838
public nextDepth$: Observable<number>;
39+
sub: Subscription;
3940

4041
constructor(
4142
private routerExt: RouterExtensions,
@@ -48,10 +49,18 @@ export class SecondComponent implements OnInit, OnDestroy {
4849
}
4950

5051
ngOnInit() {
52+
this.sub = this.route.queryParams.subscribe((params) => {
53+
console.log("");
54+
console.log("");
55+
console.log(params);
56+
console.log("");
57+
console.log("");
58+
});
5159
console.log("SecondComponent - ngOnInit()");
5260
}
5361

5462
ngOnDestroy() {
63+
this.sub.unsubscribe();
5564
console.log("SecondComponent - ngOnDestroy()");
5665
}
5766

Diff for: nativescript-angular/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,6 @@
7373
"typescript": "~3.8.3",
7474
"zone.js": "^0.10.3",
7575
"nativescript-typedoc-theme": "git://github.com/NativeScript/nativescript-typedoc-theme.git#master",
76-
"typedoc": "^0.13.0"
76+
"typedoc": "0.15.0"
7777
}
7878
}

Diff for: nativescript-angular/router/ns-location-strategy.ts

+18-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Injectable } from "@angular/core";
22
import { LocationStrategy } from "@angular/common";
3-
import { DefaultUrlSerializer, UrlSegmentGroup, UrlTree, ActivatedRouteSnapshot } from "@angular/router";
3+
import { DefaultUrlSerializer, UrlSegmentGroup, UrlTree, ActivatedRouteSnapshot, Params } from "@angular/router";
44
import { routerLog, routerError, isLogEnabled } from "../trace";
55
import { NavigationTransition, Frame } from "@nativescript/core/ui/frame";
66
import { isPresent } from "../lang-facade";
@@ -85,6 +85,7 @@ const defaultNavOptions: NavigationOptions = {
8585
};
8686

8787
export interface LocationState {
88+
queryParams: Params;
8889
segmentGroup: UrlSegmentGroup;
8990
isRootSegmentGroup: boolean;
9091
isPageNavigation: boolean;
@@ -131,6 +132,7 @@ export class NSLocationStrategy extends LocationStrategy {
131132
}
132133

133134
const urlSerializer = new DefaultUrlSerializer();
135+
tree.queryParams = state.queryParams;
134136
const url = urlSerializer.serialize(tree);
135137
if (isLogEnabled()) {
136138
routerLog("NSLocationStrategy.path(): " + url);
@@ -165,10 +167,11 @@ export class NSLocationStrategy extends LocationStrategy {
165167
const outletKey = this.getOutletKey(this.getSegmentGroupFullPath(segmentGroup), "primary");
166168
const outlet = this.findOutlet(outletKey);
167169

168-
if (outlet && this.updateStates(outlet, segmentGroup)) {
170+
if (outlet && this.updateStates(outlet, segmentGroup, this.currentUrlTree.queryParams)) {
169171
this.currentOutlet = outlet; // If states updated
170172
} else if (!outlet) {
171-
const rootOutlet = this.createOutlet("primary", null, segmentGroup, null);
173+
// tslint:disable-next-line:max-line-length
174+
const rootOutlet = this.createOutlet("primary", null, segmentGroup, null, null, this.currentUrlTree.queryParams);
172175
this.currentOutlet = rootOutlet;
173176
}
174177

@@ -197,15 +200,15 @@ export class NSLocationStrategy extends LocationStrategy {
197200
const containsLastState = outlet && outlet.containsTopState(currentSegmentGroup.toString());
198201
if (!outlet) {
199202
// tslint:disable-next-line:max-line-length
200-
outlet = this.createOutlet(outletKey, outletPath, currentSegmentGroup, parentOutlet, this._modalNavigationDepth);
203+
outlet = this.createOutlet(outletKey, outletPath, currentSegmentGroup, parentOutlet, this._modalNavigationDepth, this.currentUrlTree.queryParams);
201204
this.currentOutlet = outlet;
202205
} else if (this._modalNavigationDepth > 0 && outlet.showingModal && !containsLastState) {
203206
// Navigation inside modal view.
204-
this.upsertModalOutlet(outlet, currentSegmentGroup);
207+
this.upsertModalOutlet(outlet, currentSegmentGroup, this.currentUrlTree.queryParams);
205208
} else {
206209
outlet.parent = parentOutlet;
207210

208-
if (this.updateStates(outlet, currentSegmentGroup)) {
211+
if (this.updateStates(outlet, currentSegmentGroup, this.currentUrlTree.queryParams)) {
209212
this.currentOutlet = outlet; // If states updated
210213
}
211214
}
@@ -604,15 +607,16 @@ export class NSLocationStrategy extends LocationStrategy {
604607
return outlet;
605608
}
606609

607-
private updateStates(outlet: Outlet, currentSegmentGroup: UrlSegmentGroup): boolean {
610+
private updateStates(outlet: Outlet, currentSegmentGroup: UrlSegmentGroup, queryParams: Params): boolean {
608611
const isNewPage = outlet.states.length === 0;
609612
const lastState = outlet.states[outlet.states.length - 1];
610613
const equalStateUrls = outlet.containsTopState(currentSegmentGroup.toString());
611614

612615
const locationState: LocationState = {
613616
segmentGroup: currentSegmentGroup,
614617
isRootSegmentGroup: false,
615-
isPageNavigation: isNewPage
618+
isPageNavigation: isNewPage,
619+
queryParams: {...queryParams}
616620
};
617621

618622
if (!lastState || !equalStateUrls) {
@@ -645,14 +649,15 @@ export class NSLocationStrategy extends LocationStrategy {
645649
}
646650

647651
// tslint:disable-next-line:max-line-length
648-
private createOutlet(outletKey: string, path: string, segmentGroup: any, parent: Outlet, modalNavigation?: number): Outlet {
652+
private createOutlet(outletKey: string, path: string, segmentGroup: any, parent: Outlet, modalNavigation?: number, queryParams: Params = {}): Outlet {
649653
const pathByOutlets = this.getPathByOutlets(segmentGroup);
650654
const newOutlet = new Outlet(outletKey, path, pathByOutlets, modalNavigation);
651655

652656
const locationState: LocationState = {
653657
segmentGroup: segmentGroup,
654658
isRootSegmentGroup: false,
655-
isPageNavigation: true // It is a new OutletNode.
659+
isPageNavigation: true, // It is a new OutletNode.
660+
queryParams: {...queryParams}
656661
};
657662

658663
newOutlet.states = [locationState];
@@ -719,7 +724,7 @@ export class NSLocationStrategy extends LocationStrategy {
719724
}
720725
}
721726

722-
private upsertModalOutlet(parentOutlet: Outlet, segmentedGroup: UrlSegmentGroup) {
727+
private upsertModalOutlet(parentOutlet: Outlet, segmentedGroup: UrlSegmentGroup, queryParams: Params) {
723728
let currentModalOutlet = this.findOutletByModal(this._modalNavigationDepth);
724729

725730
// We want to treat every p-r-o as a standalone Outlet.
@@ -734,9 +739,9 @@ export class NSLocationStrategy extends LocationStrategy {
734739
const outletPath = parentOutlet.peekState().segmentGroup.toString();
735740
const outletKey = this.getOutletKey(outletPath, outletName);
736741
// tslint:disable-next-line:max-line-length
737-
currentModalOutlet = this.createOutlet(outletKey, outletPath, segmentedGroup, parentOutlet, this._modalNavigationDepth);
742+
currentModalOutlet = this.createOutlet(outletKey, outletPath, segmentedGroup, parentOutlet, this._modalNavigationDepth, queryParams);
738743
this.currentOutlet = currentModalOutlet;
739-
} else if (this.updateStates(currentModalOutlet, segmentedGroup)) {
744+
} else if (this.updateStates(currentModalOutlet, segmentedGroup, queryParams)) {
740745
this.currentOutlet = currentModalOutlet; // If states updated
741746
}
742747
}

Diff for: tests/app/tests/ns-location-strategy.ts

+41
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ function createState(
135135
segmentGroup: isRoot ? stateUrlTree.root : rootOutlets[outletName],
136136
isPageNavigation: isPageNav,
137137
isRootSegmentGroup: isRoot,
138+
queryParams: stateUrlTree.queryParams
138139
};
139140
}
140141

@@ -269,6 +270,46 @@ describe("NSLocationStrategy", () => {
269270
assert.equal(popCount, 0); // no onPopState when replacing
270271
});
271272

273+
it("back() preserves query params", () => {
274+
const { strategy } = initStrategy("/?param=1");
275+
let popCount = 0;
276+
strategy.onPopState(() => {
277+
popCount++;
278+
});
279+
280+
strategy.pushState(null, "test", "/test", null);
281+
assert.equal(strategy.path(), "/test");
282+
assert.equal(popCount, 0);
283+
284+
strategy.pushState(null, "test2", "/test2?param2=2", null);
285+
assert.equal(strategy.path(), "/test2?param2=2");
286+
assert.equal(popCount, 0);
287+
288+
strategy.pushState(null, "test3", "/test3?param3=3", null);
289+
assert.equal(strategy.path(), "/test3?param3=3");
290+
assert.equal(popCount, 0);
291+
292+
strategy.pushState(null, "test4", "/test4", null);
293+
assert.equal(strategy.path(), "/test4");
294+
assert.equal(popCount, 0);
295+
296+
strategy.back();
297+
assert.equal(strategy.path(), "/test3?param3=3");
298+
assert.equal(popCount, 1);
299+
300+
strategy.back();
301+
assert.equal(strategy.path(), "/test2?param2=2");
302+
assert.equal(popCount, 2);
303+
304+
strategy.back();
305+
assert.equal(strategy.path(), "/test");
306+
assert.equal(popCount, 3);
307+
308+
strategy.back();
309+
assert.equal(strategy.path(), "/?param=1");
310+
assert.equal(popCount, 4);
311+
});
312+
272313
it("pushState() with page navigation", () => {
273314
const { strategy } = initStrategy("/");
274315
const outletName = "primary";

0 commit comments

Comments
 (0)