Skip to content

Commit 9d563f5

Browse files
committed
fix(urlSerializer): improve findLinkByComponentData
1 parent 1158a96 commit 9d563f5

File tree

3 files changed

+134
-2
lines changed

3 files changed

+134
-2
lines changed

src/navigation/nav-util.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export interface NavLink {
118118
partsLen?: number;
119119
staticLen?: number;
120120
dataLen?: number;
121+
dataKeys?: {[key: string]: boolean};
121122
defaultHistory?: any[];
122123
}
123124

src/navigation/test/url-serializer.spec.ts

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
import { NavLink, NavSegment } from '../nav-util';
2-
import { UrlSerializer, isPartMatch, fillMatchedUrlParts, parseUrlParts, createMatchedData, normalizeLinks } from '../url-serializer';
2+
import { UrlSerializer, isPartMatch, fillMatchedUrlParts, parseUrlParts, createMatchedData, normalizeLinks, findLinkByComponentData } from '../url-serializer';
33
import { mockDeepLinkConfig, noop, MockView1, MockView2, MockView3, MockView4, MockView5 } from '../../util/mock-providers';
44

55

66
describe('UrlSerializer', () => {
77

88
describe('serializeComponent', () => {
99

10+
it('should create segement when config has multiple links to same component', () => {
11+
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
12+
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view/:param1' };
13+
const link3 = { component: MockView1, name: 'viewthree', segment: 'view/:param1/:param2' };
14+
15+
serializer = mockSerializer([link1, link2, link3]);
16+
serializer.createSegment = noop;
17+
spyOn(serializer, 'createSegment');
18+
serializer.serializeComponent(MockView1, null);
19+
expect(serializer.createSegment).toHaveBeenCalledWith(link1, null);
20+
});
21+
1022
it('should create segment if component found in links', () => {
1123
serializer.createSegment = noop;
1224
spyOn(serializer, 'createSegment');
@@ -533,6 +545,88 @@ describe('UrlSerializer', () => {
533545

534546
});
535547

548+
describe('findLinkByComponentData', () => {
549+
550+
it('should get matching link by component w/ data and multiple links using same component, 2 matches', () => {
551+
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
552+
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view/:param1' };
553+
const link3 = { component: MockView1, name: 'viewthree', segment: 'view/:param1/:param2' };
554+
555+
let links = normalizeLinks([link1, link2, link3]);
556+
557+
let foundLink = findLinkByComponentData(links, MockView1, {
558+
param1: false,
559+
param2: 0,
560+
param3: 0
561+
});
562+
expect(foundLink.name).toEqual('viewthree');
563+
});
564+
565+
it('should get matching link by component w/ data and multiple links using same component, 1 match', () => {
566+
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
567+
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view/:param1' };
568+
const link3 = { component: MockView1, name: 'viewthree', segment: 'view/:param1/:param2' };
569+
570+
let links = normalizeLinks([link1, link2, link3]);
571+
572+
let foundLink = findLinkByComponentData(links, MockView1, {
573+
param1: false,
574+
param3: 0
575+
});
576+
expect(foundLink.name).toEqual('viewtwo');
577+
});
578+
579+
it('should get matching link by component w/ no data and multiple links using same component', () => {
580+
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
581+
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view/:param1' };
582+
const link3 = { component: MockView1, name: 'viewthree', segment: 'view/:param1/:param2' };
583+
584+
let links = normalizeLinks([link1, link2, link3]);
585+
586+
let foundLink = findLinkByComponentData(links, MockView1, null);
587+
expect(foundLink.name).toEqual('viewone');
588+
});
589+
590+
it('should get matching link by component data and link data', () => {
591+
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
592+
const link2 = { component: MockView2, name: 'viewtwo', segment: 'view/:param1' };
593+
const link3 = { component: MockView3, name: 'viewthree', segment: 'view/:param1/:param2' };
594+
595+
let links = normalizeLinks([link1, link2, link3]);
596+
597+
let foundLink = findLinkByComponentData(links, MockView3, {
598+
param1: null,
599+
param2: false,
600+
param3: 0,
601+
param4: 'hello'
602+
});
603+
expect(foundLink.name).toEqual('viewthree');
604+
});
605+
606+
it('should get matching link by component without data and link without data', () => {
607+
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
608+
const link2 = { component: MockView2, name: 'viewtwo', segment: 'view/:param1' };
609+
const link3 = { component: MockView3, name: 'viewthree', segment: 'view/:param1/:param2' };
610+
611+
let links = normalizeLinks([link1, link2, link3]);
612+
613+
let foundLink = findLinkByComponentData(links, MockView1, null);
614+
expect(foundLink.name).toEqual('viewone');
615+
});
616+
617+
it('should get no matching link by component without data, but link requires data', () => {
618+
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
619+
const link2 = { component: MockView2, name: 'viewtwo', segment: 'view/:param1' };
620+
const link3 = { component: MockView3, name: 'viewthree', segment: 'view/:param1/:param2' };
621+
622+
let links = normalizeLinks([link1, link2, link3]);
623+
624+
let foundLink = findLinkByComponentData(links, MockView2, null);
625+
expect(foundLink).toEqual(null);
626+
});
627+
628+
});
629+
536630
describe('normalizeLinks', () => {
537631

538632
it('should sort with four parts, the most number of paths w/out data first', () => {

src/navigation/url-serializer.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export class UrlSerializer {
5959
*/
6060
serializeComponent(component: any, data: any): NavSegment {
6161
if (component) {
62-
const link = this.links.find(l => component === l.component || component.name === l.name);
62+
const link = findLinkByComponentData(this.links, component, data);
6363
if (link) {
6464
return this.createSegment(link, data);
6565
}
@@ -203,6 +203,41 @@ export const createMatchedData = (matchedUrlParts: string[], link: NavLink): any
203203
return data;
204204
};
205205

206+
export const findLinkByComponentData = (links: NavLink[], component: any, instanceData: any): NavLink => {
207+
let foundLink: NavLink = null;
208+
let foundLinkDataMatches = -1;
209+
210+
for (var i = 0; i < links.length; i++) {
211+
var link = links[i];
212+
if (link.component === component) {
213+
// ok, so the component matched, but multiple links can point
214+
// to the same component, so let's make sure this is the right link
215+
var dataMatches = 0;
216+
if (instanceData) {
217+
var instanceDataKeys = Object.keys(instanceData);
218+
219+
// this link has data
220+
for (var j = 0; j < instanceDataKeys.length; j++) {
221+
if (isPresent(link.dataKeys[instanceDataKeys[j]])) {
222+
dataMatches++;
223+
}
224+
}
225+
226+
} else if (link.dataLen) {
227+
// this component does not have data but the link does
228+
continue;
229+
}
230+
231+
if (dataMatches >= foundLinkDataMatches) {
232+
foundLink = link;
233+
foundLinkDataMatches = dataMatches;
234+
}
235+
}
236+
}
237+
238+
return foundLink;
239+
};
240+
206241
export const normalizeLinks = (links: NavLink[]): NavLink[] => {
207242
for (var i = 0, ilen = links.length; i < ilen; i++) {
208243
var link = links[i];
@@ -211,6 +246,7 @@ export const normalizeLinks = (links: NavLink[]): NavLink[] => {
211246
link.segment = link.name;
212247
}
213248

249+
link.dataKeys = {};
214250
link.parts = link.segment.split('/');
215251
link.partsLen = link.parts.length;
216252

@@ -222,6 +258,7 @@ export const normalizeLinks = (links: NavLink[]): NavLink[] => {
222258
if (link.parts[j].charAt(0) === ':') {
223259
link.dataLen++;
224260
stillCountingStatic = false;
261+
link.dataKeys[link.parts[j].substring(1)] = true;
225262

226263
} else if (stillCountingStatic) {
227264
link.staticLen++;

0 commit comments

Comments
 (0)