Skip to content

Commit

Permalink
fix(urlSerializer): improve findLinkByComponentData
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdbradley committed Sep 16, 2016
1 parent 1158a96 commit 9d563f5
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/navigation/nav-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export interface NavLink {
partsLen?: number;
staticLen?: number;
dataLen?: number;
dataKeys?: {[key: string]: boolean};
defaultHistory?: any[];
}

Expand Down
96 changes: 95 additions & 1 deletion src/navigation/test/url-serializer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import { NavLink, NavSegment } from '../nav-util';
import { UrlSerializer, isPartMatch, fillMatchedUrlParts, parseUrlParts, createMatchedData, normalizeLinks } from '../url-serializer';
import { UrlSerializer, isPartMatch, fillMatchedUrlParts, parseUrlParts, createMatchedData, normalizeLinks, findLinkByComponentData } from '../url-serializer';
import { mockDeepLinkConfig, noop, MockView1, MockView2, MockView3, MockView4, MockView5 } from '../../util/mock-providers';


describe('UrlSerializer', () => {

describe('serializeComponent', () => {

it('should create segement when config has multiple links to same component', () => {
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view/:param1' };
const link3 = { component: MockView1, name: 'viewthree', segment: 'view/:param1/:param2' };

serializer = mockSerializer([link1, link2, link3]);
serializer.createSegment = noop;
spyOn(serializer, 'createSegment');
serializer.serializeComponent(MockView1, null);
expect(serializer.createSegment).toHaveBeenCalledWith(link1, null);
});

it('should create segment if component found in links', () => {
serializer.createSegment = noop;
spyOn(serializer, 'createSegment');
Expand Down Expand Up @@ -533,6 +545,88 @@ describe('UrlSerializer', () => {

});

describe('findLinkByComponentData', () => {

it('should get matching link by component w/ data and multiple links using same component, 2 matches', () => {
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view/:param1' };
const link3 = { component: MockView1, name: 'viewthree', segment: 'view/:param1/:param2' };

let links = normalizeLinks([link1, link2, link3]);

let foundLink = findLinkByComponentData(links, MockView1, {
param1: false,
param2: 0,
param3: 0
});
expect(foundLink.name).toEqual('viewthree');
});

it('should get matching link by component w/ data and multiple links using same component, 1 match', () => {
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view/:param1' };
const link3 = { component: MockView1, name: 'viewthree', segment: 'view/:param1/:param2' };

let links = normalizeLinks([link1, link2, link3]);

let foundLink = findLinkByComponentData(links, MockView1, {
param1: false,
param3: 0
});
expect(foundLink.name).toEqual('viewtwo');
});

it('should get matching link by component w/ no data and multiple links using same component', () => {
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view/:param1' };
const link3 = { component: MockView1, name: 'viewthree', segment: 'view/:param1/:param2' };

let links = normalizeLinks([link1, link2, link3]);

let foundLink = findLinkByComponentData(links, MockView1, null);
expect(foundLink.name).toEqual('viewone');
});

it('should get matching link by component data and link data', () => {
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
const link2 = { component: MockView2, name: 'viewtwo', segment: 'view/:param1' };
const link3 = { component: MockView3, name: 'viewthree', segment: 'view/:param1/:param2' };

let links = normalizeLinks([link1, link2, link3]);

let foundLink = findLinkByComponentData(links, MockView3, {
param1: null,
param2: false,
param3: 0,
param4: 'hello'
});
expect(foundLink.name).toEqual('viewthree');
});

it('should get matching link by component without data and link without data', () => {
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
const link2 = { component: MockView2, name: 'viewtwo', segment: 'view/:param1' };
const link3 = { component: MockView3, name: 'viewthree', segment: 'view/:param1/:param2' };

let links = normalizeLinks([link1, link2, link3]);

let foundLink = findLinkByComponentData(links, MockView1, null);
expect(foundLink.name).toEqual('viewone');
});

it('should get no matching link by component without data, but link requires data', () => {
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
const link2 = { component: MockView2, name: 'viewtwo', segment: 'view/:param1' };
const link3 = { component: MockView3, name: 'viewthree', segment: 'view/:param1/:param2' };

let links = normalizeLinks([link1, link2, link3]);

let foundLink = findLinkByComponentData(links, MockView2, null);
expect(foundLink).toEqual(null);
});

});

describe('normalizeLinks', () => {

it('should sort with four parts, the most number of paths w/out data first', () => {
Expand Down
39 changes: 38 additions & 1 deletion src/navigation/url-serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class UrlSerializer {
*/
serializeComponent(component: any, data: any): NavSegment {
if (component) {
const link = this.links.find(l => component === l.component || component.name === l.name);
const link = findLinkByComponentData(this.links, component, data);
if (link) {
return this.createSegment(link, data);
}
Expand Down Expand Up @@ -203,6 +203,41 @@ export const createMatchedData = (matchedUrlParts: string[], link: NavLink): any
return data;
};

export const findLinkByComponentData = (links: NavLink[], component: any, instanceData: any): NavLink => {
let foundLink: NavLink = null;
let foundLinkDataMatches = -1;

for (var i = 0; i < links.length; i++) {
var link = links[i];
if (link.component === component) {
// ok, so the component matched, but multiple links can point
// to the same component, so let's make sure this is the right link
var dataMatches = 0;
if (instanceData) {
var instanceDataKeys = Object.keys(instanceData);

// this link has data
for (var j = 0; j < instanceDataKeys.length; j++) {
if (isPresent(link.dataKeys[instanceDataKeys[j]])) {
dataMatches++;
}
}

} else if (link.dataLen) {
// this component does not have data but the link does
continue;
}

if (dataMatches >= foundLinkDataMatches) {
foundLink = link;
foundLinkDataMatches = dataMatches;
}
}
}

return foundLink;
};

export const normalizeLinks = (links: NavLink[]): NavLink[] => {
for (var i = 0, ilen = links.length; i < ilen; i++) {
var link = links[i];
Expand All @@ -211,6 +246,7 @@ export const normalizeLinks = (links: NavLink[]): NavLink[] => {
link.segment = link.name;
}

link.dataKeys = {};
link.parts = link.segment.split('/');
link.partsLen = link.parts.length;

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

} else if (stillCountingStatic) {
link.staticLen++;
Expand Down

0 comments on commit 9d563f5

Please sign in to comment.