added tests for breadcrumbs service and component

This commit is contained in:
lotte
2020-02-26 14:44:34 +01:00
parent b4a63fccf4
commit 4ae8997ada
17 changed files with 280 additions and 29 deletions

View File

@@ -266,6 +266,8 @@
"collection.edit.head": "Edit Collection", "collection.edit.head": "Edit Collection",
"collection.edit.breadcrumbs": "Edit Collection",
"collection.edit.item-mapper.cancel": "Cancel", "collection.edit.item-mapper.cancel": "Cancel",
@@ -450,6 +452,7 @@
"community.edit.head": "Edit Community", "community.edit.head": "Edit Community",
"community.edit.breadcrumbs": "Edit Community",
"community.edit.logo.label": "Community logo", "community.edit.logo.label": "Community logo",
@@ -657,6 +660,8 @@
"item.edit.head": "Edit Item", "item.edit.head": "Edit Item",
"item.edit.breadcrumbs": "Edit Item",
"item.edit.item-mapper.buttons.add": "Map item to selected collections", "item.edit.item-mapper.buttons.add": "Map item to selected collections",
@@ -1077,6 +1082,8 @@
"login.title": "Login", "login.title": "Login",
"login.breadcrumbs": "Login",
"logout.form.header": "Log out from DSpace", "logout.form.header": "Log out from DSpace",
@@ -1473,6 +1480,7 @@
"search.title": "DSpace Angular :: Search", "search.title": "DSpace Angular :: Search",
"search.breadcrumbs": "Search",
"search.filters.applied.f.author": "Author", "search.filters.applied.f.author": "Author",

View File

@@ -21,7 +21,7 @@ export function getCollectionPageRoute(collectionId: string) {
} }
export function getCollectionEditPath(id: string) { export function getCollectionEditPath(id: string) {
return new URLCombiner(getCollectionModulePath(), COLLECTION_EDIT_PATH.replace(/:id/, id)).toString() return new URLCombiner(getCollectionModulePath(), id, COLLECTION_EDIT_PATH).toString()
} }
export function getCollectionCreatePath() { export function getCollectionCreatePath() {

View File

@@ -5,6 +5,7 @@ import { CollectionMetadataComponent } from './collection-metadata/collection-me
import { CollectionRolesComponent } from './collection-roles/collection-roles.component'; import { CollectionRolesComponent } from './collection-roles/collection-roles.component';
import { CollectionSourceComponent } from './collection-source/collection-source.component'; import { CollectionSourceComponent } from './collection-source/collection-source.component';
import { CollectionCurateComponent } from './collection-curate/collection-curate.component'; import { CollectionCurateComponent } from './collection-curate/collection-curate.component';
import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
/** /**
* Routing module that handles the routing for the Edit Collection page administrator functionality * Routing module that handles the routing for the Edit Collection page administrator functionality
@@ -14,6 +15,10 @@ import { CollectionCurateComponent } from './collection-curate/collection-curate
RouterModule.forChild([ RouterModule.forChild([
{ {
path: '', path: '',
resolve: {
breadcrumb: I18nBreadcrumbResolver
},
data: { breadcrumbKey: 'collection.edit' },
component: EditCollectionPageComponent, component: EditCollectionPageComponent,
children: [ children: [
{ {

View File

@@ -20,7 +20,7 @@ export function getCommunityPageRoute(communityId: string) {
} }
export function getCommunityEditPath(id: string) { export function getCommunityEditPath(id: string) {
return new URLCombiner(getCommunityModulePath(), COMMUNITY_EDIT_PATH.replace(/:id/, id)).toString() return new URLCombiner(getCommunityModulePath(), id, COMMUNITY_EDIT_PATH).toString()
} }
export function getCommunityCreatePath() { export function getCommunityCreatePath() {

View File

@@ -5,6 +5,7 @@ import { NgModule } from '@angular/core';
import { CommunityMetadataComponent } from './community-metadata/community-metadata.component'; import { CommunityMetadataComponent } from './community-metadata/community-metadata.component';
import { CommunityRolesComponent } from './community-roles/community-roles.component'; import { CommunityRolesComponent } from './community-roles/community-roles.component';
import { CommunityCurateComponent } from './community-curate/community-curate.component'; import { CommunityCurateComponent } from './community-curate/community-curate.component';
import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
/** /**
* Routing module that handles the routing for the Edit Community page administrator functionality * Routing module that handles the routing for the Edit Community page administrator functionality
@@ -14,6 +15,10 @@ import { CommunityCurateComponent } from './community-curate/community-curate.co
RouterModule.forChild([ RouterModule.forChild([
{ {
path: '', path: '',
resolve: {
breadcrumb: I18nBreadcrumbResolver
},
data: { breadcrumbKey: 'community.edit' },
component: EditCommunityPageComponent, component: EditCommunityPageComponent,
children: [ children: [
{ {

View File

@@ -33,7 +33,7 @@ const ITEM_EDIT_MOVE_PATH = 'move';
resolve: { resolve: {
breadcrumb: I18nBreadcrumbResolver breadcrumb: I18nBreadcrumbResolver
}, },
data: { breadcrumbKey: 'edit.item' }, data: { breadcrumbKey: 'item.edit' },
children: [ children: [
{ {
path: '', path: '',

View File

@@ -16,7 +16,7 @@ export function getItemPageRoute(itemId: string) {
} }
export function getItemEditPath(id: string) { export function getItemEditPath(id: string) {
return new URLCombiner(getItemModulePath(), ITEM_EDIT_PATH.replace(/:id/, id)).toString() return new URLCombiner(getItemModulePath(), id, ITEM_EDIT_PATH).toString()
} }
const ITEM_EDIT_PATH = 'edit'; const ITEM_EDIT_PATH = 'edit';

View File

@@ -7,7 +7,7 @@ import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.reso
@NgModule({ @NgModule({
imports: [ imports: [
RouterModule.forChild([ RouterModule.forChild([
{ path: '', pathMatch: 'full', component: LoginPageComponent, resolve: { breadcrumb: I18nBreadcrumbResolver }, data: { breadcrumbKey: 'Search', title: 'login.title' } } { path: '', pathMatch: 'full', component: LoginPageComponent, resolve: { breadcrumb: I18nBreadcrumbResolver }, data: { breadcrumbKey: 'login', title: 'login.title' } }
]) ])
] ]
}) })

View File

@@ -11,7 +11,7 @@ import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.ser
imports: [ imports: [
RouterModule.forChild([{ RouterModule.forChild([{
path: '', path: '',
resolve: { breadcrumb: I18nBreadcrumbResolver }, data: { title: 'search.title', breadcrumbKey: 'Search' }, resolve: { breadcrumb: I18nBreadcrumbResolver }, data: { title: 'search.title', breadcrumbKey: 'search' },
children: [ children: [
{ path: '', component: SearchPageComponent }, { path: '', component: SearchPageComponent },
{ path: ':configuration', component: ConfigurationSearchPageComponent, canActivate: [ConfigurationSearchPageGuard] } { path: ':configuration', component: ConfigurationSearchPageComponent, canActivate: [ConfigurationSearchPageGuard] }

View File

@@ -1,14 +1,80 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BreadcrumbsComponent } from './breadcrumbs.component'; import { BreadcrumbsComponent } from './breadcrumbs.component';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { Observable, of as observableOf } from 'rxjs';
import { RouterTestingModule } from '@angular/router/testing';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { MockTranslateLoader } from '../shared/testing/mock-translate-loader';
import { BreadcrumbConfig } from './breadcrumb/breadcrumb-config.model';
import { BreadcrumbsService } from '../core/breadcrumbs/breadcrumbs.service';
import { Breadcrumb } from './breadcrumb/breadcrumb.model';
import { getTestScheduler } from 'jasmine-marbles';
class TestBreadcrumbsService implements BreadcrumbsService<string> {
getBreadcrumbs(key: string, url: string): Observable<Breadcrumb[]> {
return observableOf([new Breadcrumb(key, url)]);
}
}
describe('BreadcrumbsComponent', () => { describe('BreadcrumbsComponent', () => {
let component: BreadcrumbsComponent; let component: BreadcrumbsComponent;
let fixture: ComponentFixture<BreadcrumbsComponent>; let fixture: ComponentFixture<BreadcrumbsComponent>;
let router: any;
let route: any;
let breadcrumbProvider;
let breadcrumbConfigA: BreadcrumbConfig<string>;
let breadcrumbConfigB: BreadcrumbConfig<string>;
let expectedBreadcrumbs;
function init() {
breadcrumbProvider = new TestBreadcrumbsService();
breadcrumbConfigA = { provider: breadcrumbProvider, key: 'example.path', url: 'example.com' };
breadcrumbConfigB = { provider: breadcrumbProvider, key: 'another.path', url: 'another.com' };
route = {
root: {
snapshot: {
data: { breadcrumb: breadcrumbConfigA },
routeConfig: { resolve: { breadcrumb: {} } }
},
firstChild: {
snapshot: {
// Example without resolver should be ignored
data: { breadcrumb: breadcrumbConfigA },
},
firstChild: {
snapshot: {
data: { breadcrumb: breadcrumbConfigB },
routeConfig: { resolve: { breadcrumb: {} } }
}
}
}
}
};
expectedBreadcrumbs = [
new Breadcrumb(breadcrumbConfigA.key, breadcrumbConfigA.url),
new Breadcrumb(breadcrumbConfigB.key, breadcrumbConfigB.url)
]
}
beforeEach(async(() => { beforeEach(async(() => {
init();
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ BreadcrumbsComponent ] declarations: [BreadcrumbsComponent],
imports: [RouterTestingModule.withRoutes([]), TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
}
})],
providers: [
{ provide: ActivatedRoute, useValue: route }
]
}) })
.compileComponents(); .compileComponents();
})); }));
@@ -16,10 +82,30 @@ describe('BreadcrumbsComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(BreadcrumbsComponent); fixture = TestBed.createComponent(BreadcrumbsComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
router = TestBed.get(Router);
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
describe('ngOnInit', () => {
beforeEach(() => {
spyOn(component, 'resolveBreadcrumbs').and.returnValue(observableOf([]))
});
it('should call resolveBreadcrumb on init', () => {
router.events = observableOf(new NavigationEnd(0, '', ''));
component.ngOnInit();
expect(component.resolveBreadcrumbs).toHaveBeenCalledWith(route.root);
})
});
describe('resolveBreadcrumbs', () => {
it('should return the correct breadcrumbs', () => {
const breadcrumbs = component.resolveBreadcrumbs(route.root);
getTestScheduler().expectObservable(breadcrumbs).toBe('(a|)', { a: expectedBreadcrumbs })
})
})
}); });

View File

@@ -1,17 +1,16 @@
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { Breadcrumb } from './breadcrumb/breadcrumb.model'; import { Breadcrumb } from './breadcrumb/breadcrumb.model';
import { hasValue, isNotUndefined } from '../shared/empty.util'; import { hasNoValue, hasValue, isNotUndefined } from '../shared/empty.util';
import { filter, map, switchMap, tap } from 'rxjs/operators'; import { filter, map, switchMap, tap } from 'rxjs/operators';
import { combineLatest, Observable, Subscription, of as observableOf } from 'rxjs'; import { combineLatest, Observable, Subscription, of as observableOf } from 'rxjs';
import { BreadcrumbConfig } from './breadcrumb/breadcrumb-config.model';
@Component({ @Component({
selector: 'ds-breadcrumbs', selector: 'ds-breadcrumbs',
templateUrl: './breadcrumbs.component.html', templateUrl: './breadcrumbs.component.html',
styleUrls: ['./breadcrumbs.component.scss'] styleUrls: ['./breadcrumbs.component.scss']
}) })
export class BreadcrumbsComponent implements OnDestroy { export class BreadcrumbsComponent implements OnInit, OnDestroy {
breadcrumbs: Breadcrumb[]; breadcrumbs: Breadcrumb[];
showBreadcrumbs: boolean; showBreadcrumbs: boolean;
subscription: Subscription; subscription: Subscription;
@@ -20,21 +19,24 @@ export class BreadcrumbsComponent implements OnDestroy {
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router private router: Router
) { ) {
}
ngOnInit(): void {
this.subscription = this.router.events.pipe( this.subscription = this.router.events.pipe(
filter((e): e is NavigationEnd => e instanceof NavigationEnd), filter((e): e is NavigationEnd => e instanceof NavigationEnd),
tap(() => this.reset()), tap(() => this.reset()),
switchMap(() => this.resolveBreadcrumb(this.route.root)) switchMap(() => this.resolveBreadcrumbs(this.route.root))
).subscribe((breadcrumbs) => { ).subscribe((breadcrumbs) => {
this.breadcrumbs = breadcrumbs; this.breadcrumbs = breadcrumbs;
} }
) )
} }
resolveBreadcrumb(route: ActivatedRoute): Observable<Breadcrumb[]> { resolveBreadcrumbs(route: ActivatedRoute): Observable<Breadcrumb[]> {
const data = route.snapshot.data; const data = route.snapshot.data;
const routeConfig = route.snapshot.routeConfig; const routeConfig = route.snapshot.routeConfig;
const last: boolean = route.children.length === 0; const last: boolean = hasNoValue(route.firstChild);
if (last && isNotUndefined(data.showBreadcrumbs)) { if (last && isNotUndefined(data.showBreadcrumbs)) {
this.showBreadcrumbs = data.showBreadcrumbs; this.showBreadcrumbs = data.showBreadcrumbs;
} }
@@ -45,13 +47,13 @@ export class BreadcrumbsComponent implements OnDestroy {
) { ) {
const { provider, key, url } = data.breadcrumb; const { provider, key, url } = data.breadcrumb;
if (!last) { if (!last) {
return combineLatest(provider.getBreadcrumbs(key, url), this.resolveBreadcrumb(route.firstChild)) return combineLatest(provider.getBreadcrumbs(key, url), this.resolveBreadcrumbs(route.firstChild))
.pipe(map((crumbs) => [].concat.apply([], crumbs))); .pipe(map((crumbs) => [].concat.apply([], crumbs)));
} else { } else {
return provider.getBreadcrumbs(key, url); return provider.getBreadcrumbs(key, url);
} }
} }
return !last ? this.resolveBreadcrumb(route.firstChild) : observableOf([]); return !last ? this.resolveBreadcrumbs(route.firstChild) : observableOf([]);
} }
ngOnDestroy(): void { ngOnDestroy(): void {

View File

@@ -1,7 +1,5 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { DSOBreadcrumbsService } from './dso-breadcrumbs.service'; import { DSOBreadcrumbsService } from './dso-breadcrumbs.service';
import { ItemDataService } from '../data/item-data.service';
import { Item } from '../shared/item.model';
import { DSOBreadcrumbResolver } from './dso-breadcrumb.resolver'; import { DSOBreadcrumbResolver } from './dso-breadcrumb.resolver';
import { Collection } from '../shared/collection.model'; import { Collection } from '../shared/collection.model';
import { CollectionDataService } from '../data/collection-data.service'; import { CollectionDataService } from '../data/collection-data.service';

View File

@@ -0,0 +1,117 @@
import { async, TestBed } from '@angular/core/testing';
import { DSOBreadcrumbsService } from './dso-breadcrumbs.service';
import { getMockLinkService } from '../../shared/mocks/mock-link-service';
import { LinkService } from '../cache/builders/link.service';
import { Item } from '../shared/item.model';
import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
import { DSpaceObject } from '../shared/dspace-object.model';
import { map } from 'rxjs/operators';
import { of as observableOf } from 'rxjs';
import { RemoteData } from '../data/remote-data';
import { hasValue } from '../../shared/empty.util';
import { Community } from '../shared/community.model';
import { Collection } from '../shared/collection.model';
import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model';
import { getItemPageRoute } from '../../+item-page/item-page-routing.module';
import { getCommunityPageRoute } from '../../+community-page/community-page-routing.module';
import { getCollectionPageRoute } from '../../+collection-page/collection-page-routing.module';
import { cold, getTestScheduler } from 'jasmine-marbles';
import { getDSOPath } from '../../app-routing.module';
fdescribe('DSOBreadcrumbsService', () => {
let service: DSOBreadcrumbsService;
let linkService: any;
let testItem;
let testCollection;
let testCommunity;
let itemPath;
let collectionPath;
let communityPath;
let itemUUID;
let collectionUUID;
let communityUUID;
let objects: DSpaceObject[];
function init() {
itemPath = '/items/';
collectionPath = '/collection/';
communityPath = '/community/';
itemUUID = '04dd18fc-03f9-4b9a-9304-ed7c313686d3';
collectionUUID = '91dfa5b5-5440-4fb4-b869-02610342f886';
communityUUID = '6c0bfa6b-ce82-4bf4-a2a8-fd7682c567e8';
testCommunity = Object.assign(new Community(),
{
type: 'community',
name: 'community',
uuid: communityUUID,
parentCommunity: observableOf(Object.assign(createSuccessfulRemoteDataObject(undefined), { statusCode: 204 })),
_links: {
parentCommunity: 'site',
self: communityPath + communityUUID
}
}
);
testCollection = Object.assign(new Collection(),
{
type: 'collection',
name: 'collection',
uuid: collectionUUID,
parentCommunity: createSuccessfulRemoteDataObject$(testCommunity),
_links: {
parentCommunity: communityPath + communityUUID,
self: communityPath + collectionUUID
}
}
);
testItem = Object.assign(new Item(),
{
type: 'item',
name: 'item',
uuid: itemUUID,
owningCollection: createSuccessfulRemoteDataObject$(testCollection),
_links: {
owningCollection: collectionPath + collectionUUID,
self: itemPath + itemUUID
}
}
);
objects = [testItem, testCollection, testCommunity];
}
beforeEach(async(() => {
init();
TestBed.configureTestingModule({
providers: [
{ provide: LinkService, useValue: getMockLinkService() }
]
}).compileComponents();
}));
beforeEach(() => {
linkService = TestBed.get(LinkService);
linkService.resolveLink.and.callFake((object, link) => object);
service = new DSOBreadcrumbsService(linkService);
});
describe('getBreadcrumbs', () => {
it('should return the breadcrumbs based on an Item', () => {
const breadcrumbs = service.getBreadcrumbs(testItem, testItem._links.self);
const expectedCrumbs = [
new Breadcrumb(testCommunity.name, getDSOPath(testCommunity)),
new Breadcrumb(testCollection.name, getDSOPath(testCollection)),
new Breadcrumb(testItem.name, getDSOPath(testItem)),
];
getTestScheduler().expectObservable(breadcrumbs).toBe('(a|)', { a: expectedCrumbs });
})
});
});

View File

@@ -26,11 +26,11 @@ export class DSOBreadcrumbsService implements BreadcrumbsService<ChildHALResourc
const crumb = new Breadcrumb(label, url); const crumb = new Breadcrumb(label, url);
const propertyName = key.getParentLinkKey(); const propertyName = key.getParentLinkKey();
return this.linkService.resolveLink(key, followLink(propertyName))[propertyName].pipe( return this.linkService.resolveLink(key, followLink(propertyName))[propertyName].pipe(
find((childRD: RemoteData<ChildHALResource & DSpaceObject>) => childRD.hasSucceeded || childRD.statusCode === 204), find((parentRD: RemoteData<ChildHALResource & DSpaceObject>) => parentRD.hasSucceeded || parentRD.statusCode === 204),
switchMap((childRD: RemoteData<ChildHALResource & DSpaceObject>) => { switchMap((parentRD: RemoteData<ChildHALResource & DSpaceObject>) => {
if (hasValue(childRD.payload)) { if (hasValue(parentRD.payload)) {
const child = childRD.payload; const parent = parentRD.payload;
return this.getBreadcrumbs(child, getDSOPath(child)) return this.getBreadcrumbs(parent, getDSOPath(parent))
} }
return observableOf([]); return observableOf([]);

View File

@@ -0,0 +1,31 @@
import { async, TestBed } from '@angular/core/testing';
import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model';
import { getTestScheduler } from 'jasmine-marbles';
import { BREADCRUMB_MESSAGE_POSTFIX, I18nBreadcrumbsService } from './i18n-breadcrumbs.service';
fdescribe('I18nBreadcrumbsService', () => {
let service: I18nBreadcrumbsService;
let exampleString;
let exampleURL;
function init() {
exampleString = 'example.string';
exampleURL = 'example.com';
}
beforeEach(async(() => {
init();
TestBed.configureTestingModule({}).compileComponents();
}));
beforeEach(() => {
service = new I18nBreadcrumbsService();
});
describe('getBreadcrumbs', () => {
it('should return a breadcrumb based on a string by adding the postfix', () => {
const breadcrumbs = service.getBreadcrumbs(exampleString, exampleURL);
getTestScheduler().expectObservable(breadcrumbs).toBe('(a|)', { a: [new Breadcrumb(exampleString + BREADCRUMB_MESSAGE_POSTFIX, exampleURL)] });
})
});
});

View File

@@ -3,11 +3,11 @@ import { BreadcrumbsService } from './breadcrumbs.service';
import { Observable, of as observableOf } from 'rxjs'; import { Observable, of as observableOf } from 'rxjs';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
export const BREADCRUMB_MESSAGE_PREFIX = 'breadcrumbs.'; export const BREADCRUMB_MESSAGE_POSTFIX = '.breadcrumbs';
@Injectable() @Injectable()
export class I18nBreadcrumbsService implements BreadcrumbsService<string> { export class I18nBreadcrumbsService implements BreadcrumbsService<string> {
getBreadcrumbs(key: string, url: string): Observable<Breadcrumb[]> { getBreadcrumbs(key: string, url: string): Observable<Breadcrumb[]> {
return observableOf([new Breadcrumb(BREADCRUMB_MESSAGE_PREFIX + key, url)]); return observableOf([new Breadcrumb(key + BREADCRUMB_MESSAGE_POSTFIX, url)]);
} }
} }

View File

@@ -12,7 +12,7 @@ import { filter, map, startWith, tap } from 'rxjs/operators';
import { getCollectionPageRoute } from '../../+collection-page/collection-page-routing.module'; import { getCollectionPageRoute } from '../../+collection-page/collection-page-routing.module';
import { getCommunityPageRoute } from '../../+community-page/community-page-routing.module'; import { getCommunityPageRoute } from '../../+community-page/community-page-routing.module';
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config'; import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
import { Router, ActivatedRoute, RouterModule, UrlSegment } from '@angular/router'; import { Router, ActivatedRoute, RouterModule, UrlSegment, Params } from '@angular/router';
import { BrowseByTypeConfig } from '../../../config/browse-by-type-config.interface'; import { BrowseByTypeConfig } from '../../../config/browse-by-type-config.interface';
import { hasValue } from '../empty.util'; import { hasValue } from '../empty.util';
@@ -76,9 +76,8 @@ export class ComcolPageBrowseByComponent implements OnInit {
}, ...this.allOptions ]; }, ...this.allOptions ];
} }
this.currentOptionId$ = this.route.url.pipe( this.currentOptionId$ = this.route.params.pipe(
filter((urlSegments: UrlSegment[]) => hasValue(urlSegments)), map((params: Params) => params.id)
map((urlSegments: UrlSegment[]) => urlSegments[urlSegments.length - 1].path)
); );
} }