diff --git a/src/app/app.routes.strategy.spec.ts b/src/app/app.routes.strategy.spec.ts new file mode 100644 index 000000000..d8b79ea3c --- /dev/null +++ b/src/app/app.routes.strategy.spec.ts @@ -0,0 +1,88 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { AppRouteReuseStrategy } from './app.routes.strategy'; +import { TestBed } from '@angular/core/testing'; +import { AppTestingModule } from './testing/app-testing.module'; + +describe('AppRouteReuseStrategy', () => { + let appRouteReuse: AppRouteReuseStrategy; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [AppTestingModule], + providers: [AppRouteReuseStrategy] + }); + + appRouteReuse = TestBed.get(AppRouteReuseStrategy); + }); + + it('should allow detach if route is configured to be reused', () => { + const route = { + routeConfig: { + data: { + reuse: true + }, + path: 'tested-path' + } + }; + expect(appRouteReuse.shouldDetach(route)).toBe(true); + }); + + it('should store on routeCache', () => { + const route = { + url: [], + routeConfig: { + data: { + reuse: true + }, + path: 'tested-path', + component: {} + }, + firstChild: null, + children: [] + }; + appRouteReuse.store(route, { route: {} }); + expect(appRouteReuse.shouldAttach(route)).toBe(true); + }); + + it('should clear routeCache on resetCache', () => { + const route = { + url: [], + routeConfig: { + data: { + reuse: true + }, + path: 'tested-path', + component: {} + }, + firstChild: null, + children: [] + }; + appRouteReuse.store(route, { route: {} }); + appRouteReuse.resetCache(); + expect(appRouteReuse.shouldAttach(route)).toBe(false); + }); +}); diff --git a/src/app/app.routes.strategy.ts b/src/app/app.routes.strategy.ts index ff5c8e58d..13415bed2 100644 --- a/src/app/app.routes.strategy.ts +++ b/src/app/app.routes.strategy.ts @@ -28,6 +28,7 @@ import { DetachedRouteHandle, ActivatedRouteSnapshot } from '@angular/router'; +import { ComponentRef } from '@angular/core'; interface RouteData { reuse: boolean; @@ -41,6 +42,23 @@ interface RouteInfo { export class AppRouteReuseStrategy implements RouteReuseStrategy { private routeCache = new Map(); + resetCache() { + this.routeCache.forEach(value => { + this.deactivateComponent(value.handle); + }); + this.routeCache.clear(); + } + + private deactivateComponent(handle: DetachedRouteHandle): void { + if (!handle) { + return; + } + const componentRef: ComponentRef = handle['componentRef']; + if (componentRef) { + componentRef.destroy(); + } + } + shouldReuseRoute( future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot diff --git a/src/app/components/search/search-input/search-input.component.ts b/src/app/components/search/search-input/search-input.component.ts index 1bf512130..e2c4f4a70 100644 --- a/src/app/components/search/search-input/search-input.component.ts +++ b/src/app/components/search/search-input/search-input.component.ts @@ -143,6 +143,7 @@ export class SearchInputComponent implements OnInit, OnDestroy { ngOnDestroy(): void { this.onDestroy$.next(true); this.onDestroy$.complete(); + this.removeContentFilters(); } onMenuOpened() { diff --git a/src/app/services/app.service.spec.ts b/src/app/services/app.service.spec.ts new file mode 100644 index 000000000..442b9bfdc --- /dev/null +++ b/src/app/services/app.service.spec.ts @@ -0,0 +1,79 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { AppService } from './app.service'; +import { TestBed } from '@angular/core/testing'; +import { AppTestingModule } from '../testing/app-testing.module'; +import { AuthenticationService } from '@alfresco/adf-core'; +import { AppRouteReuseStrategy } from '../app.routes.strategy'; +import { Subject } from 'rxjs'; + +describe('AppService', () => { + let service: AppService; + let auth: AuthenticationService; + let routeReuse: AppRouteReuseStrategy; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [AppTestingModule], + providers: [ + AppRouteReuseStrategy, + { + provide: AuthenticationService, + useValue: { + onLogin: new Subject(), + onLogout: new Subject(), + isLoggedIn: () => false + } + } + ] + }); + + routeReuse = TestBed.get(AppRouteReuseStrategy); + auth = TestBed.get(AuthenticationService); + spyOn(routeReuse, 'resetCache').and.stub(); + + service = new AppService(auth, routeReuse); + }); + + it('should reset route cache on login', async () => { + auth.onLogin.next(); + await expect(routeReuse.resetCache).toHaveBeenCalled(); + }); + + it('should reset route cache on logout', async () => { + auth.onLogout.next(); + await expect(routeReuse.resetCache).toHaveBeenCalled(); + }); + + it('should be ready after login', async () => { + let isReady = false; + service.ready$.subscribe(value => { + isReady = value; + }); + auth.onLogin.next(); + await expect(isReady).toEqual(true); + }); +}); diff --git a/src/app/services/app.service.ts b/src/app/services/app.service.ts index 24b7f86e0..259f972b1 100644 --- a/src/app/services/app.service.ts +++ b/src/app/services/app.service.ts @@ -23,9 +23,11 @@ * along with Alfresco. If not, see . */ -import { Injectable } from '@angular/core'; +import { Injectable, Inject } from '@angular/core'; import { AuthenticationService } from '@alfresco/adf-core'; import { Observable, BehaviorSubject } from 'rxjs'; +import { AppRouteReuseStrategy } from '../app.routes.strategy'; +import { RouteReuseStrategy } from '@angular/router'; @Injectable({ providedIn: 'root' @@ -34,12 +36,20 @@ export class AppService { private ready: BehaviorSubject; ready$: Observable; - constructor(auth: AuthenticationService) { + constructor( + auth: AuthenticationService, + @Inject(RouteReuseStrategy) routeStrategy: AppRouteReuseStrategy + ) { this.ready = new BehaviorSubject(auth.isLoggedIn()); this.ready$ = this.ready.asObservable(); - auth.onLogin.subscribe(e => { + auth.onLogin.subscribe(() => { + routeStrategy.resetCache(); this.ready.next(true); }); + + auth.onLogout.subscribe(() => { + routeStrategy.resetCache(); + }); } }