From 6ed812ff750fa3717939bbda9144eb28dcfb052d Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Thu, 20 Apr 2017 16:12:09 +0100 Subject: [PATCH] feat(aio): add LocationService.path() method (#16139) This enables things like embedded components easy access to a clean version of the current location path. --- aio/src/app/shared/location.service.spec.ts | 31 +++++++++++++++++++++ aio/src/app/shared/location.service.ts | 10 +++++++ aio/src/testing/location.service.ts | 2 ++ 3 files changed, 43 insertions(+) diff --git a/aio/src/app/shared/location.service.spec.ts b/aio/src/app/shared/location.service.spec.ts index d6d0dc94fb..68629b440b 100644 --- a/aio/src/app/shared/location.service.spec.ts +++ b/aio/src/app/shared/location.service.spec.ts @@ -124,6 +124,37 @@ describe('LocationService', () => { }); }); + describe('path', () => { + it('should ask Location for the current path without the hash', () => { + const location: MockLocationStrategy = injector.get(LocationStrategy); + const service: LocationService = injector.get(LocationService); + + // We cannot test this directly in the following test because the `MockLocationStrategy` + // does not remove the hash from the path, even if we do pass `false`. + + spyOn(location, 'path').and.callThrough(); + service.path(); + expect(location.path).toHaveBeenCalledWith(false); + }); + + it('should return the current location.path, with the query and trailing slash stripped off', () => { + const location: MockLocationStrategy = injector.get(LocationStrategy); + const service: LocationService = injector.get(LocationService); + + location.simulatePopState('a/b/c?foo=bar&moo=car'); + expect(service.path()).toEqual('a/b/c'); + + location.simulatePopState('c/d/e'); + expect(service.path()).toEqual('c/d/e'); + + location.simulatePopState('a/b/c/?foo=bar&moo=car'); + expect(service.path()).toEqual('a/b/c'); + + location.simulatePopState('c/d/e/'); + expect(service.path()).toEqual('c/d/e'); + }); + }); + describe('search', () => { it('should read the query from the current location.path', () => { const location: MockLocationStrategy = injector.get(LocationStrategy); diff --git a/aio/src/app/shared/location.service.ts b/aio/src/app/shared/location.service.ts index 2d1c5fa62e..3919106525 100644 --- a/aio/src/app/shared/location.service.ts +++ b/aio/src/app/shared/location.service.ts @@ -42,6 +42,16 @@ export class LocationService { return url.replace(/^\/+/, ''); } + /** + * Get the current path, without trailing slash, hash fragment or query params + */ + path(): string { + let path = this.location.path(false); + path = path.match(/[^?]*/)[0]; // strip off query + path = path.replace(/\/$/, ''); // strip off trailing slash + return path; + } + search(): { [index: string]: string; } { const search = {}; const path = this.location.path(); diff --git a/aio/src/testing/location.service.ts b/aio/src/testing/location.service.ts index 1eb3272cad..c0ef6a6551 100644 --- a/aio/src/testing/location.service.ts +++ b/aio/src/testing/location.service.ts @@ -7,6 +7,8 @@ export class MockLocationService { setSearch = jasmine.createSpy('setSearch'); go = jasmine.createSpy('Location.go').and .callFake((url: string) => this.urlSubject.next(url)); + path = jasmine.createSpy('Location.path').and + .callFake(() => this.urlSubject.getValue().split('?')[0]); handleAnchorClick = jasmine.createSpy('Location.handleAnchorClick') .and.returnValue(false); // prevent click from causing a browser navigation