From fcdcc3e6708feaaf8532a655106f65fe4940fafd Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 8 Sep 2020 10:39:55 +0300 Subject: [PATCH 01/14] feat: create replaceable-components.service --- .../packages/core/src/lib/services/index.ts | 1 + .../replaceable-components.service.ts | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts diff --git a/npm/ng-packs/packages/core/src/lib/services/index.ts b/npm/ng-packs/packages/core/src/lib/services/index.ts index c084fd4808..d3d13de20b 100644 --- a/npm/ng-packs/packages/core/src/lib/services/index.ts +++ b/npm/ng-packs/packages/core/src/lib/services/index.ts @@ -9,6 +9,7 @@ export * from './localization.service'; export * from './multi-tenancy.service'; export * from './profile-state.service'; export * from './profile.service'; +export * from './replaceable-components.service'; export * from './rest.service'; export * from './routes.service'; export * from './session-state.service'; diff --git a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts new file mode 100644 index 0000000000..418e608c49 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts @@ -0,0 +1,65 @@ +import { Injectable, NgZone } from '@angular/core'; +import { Router } from '@angular/router'; +import { ReplaceableComponents } from '../models/replaceable-components'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { noop } from '../utils/common-utils'; +import { map, filter } from 'rxjs/operators'; + +@Injectable({ providedIn: 'root' }) +export class ReplaceableComponentsService { + private components$ = new BehaviorSubject([]); + + get replaceableComponents$(): Observable { + return this.components$.asObservable(); + } + + get replaceableComponents(): ReplaceableComponents.ReplaceableComponent[] { + return this.components$.value; + } + + constructor(private ngZone: NgZone, private router: Router) {} + + // TODO: Create a shared service for route reload and more + private reloadRoute() { + const { shouldReuseRoute } = this.router.routeReuseStrategy; + const setRouteReuse = (reuse: typeof shouldReuseRoute) => { + this.router.routeReuseStrategy.shouldReuseRoute = reuse; + }; + + setRouteReuse(() => false); + this.router.navigated = false; + + this.ngZone.run(async () => { + await this.router.navigateByUrl(this.router.url).catch(noop); + setRouteReuse(shouldReuseRoute); + }); + } + + add(replaceableComponent: ReplaceableComponents.ReplaceableComponent, reload?: boolean): void { + let replaceableComponents = this.components$.value; + + const index = replaceableComponents.findIndex( + component => component.key === replaceableComponent.key, + ); + + if (index > -1) { + replaceableComponents[index] = replaceableComponent; + } else { + replaceableComponents = [...replaceableComponents, replaceableComponent]; + } + + this.components$.next(replaceableComponents); + + if (reload) this.reloadRoute(); + } + + get(replaceableComponentKey: string): ReplaceableComponents.ReplaceableComponent { + return this.replaceableComponents.find(component => component.key === replaceableComponentKey); + } + + get$(replaceableComponentKey: string): Observable { + return this.replaceableComponents$.pipe( + map(components => components.find(component => component.key === replaceableComponentKey)), + ); + } +} From a2f6235225001958db5151dbf4f2217c2c0d8d18 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 8 Sep 2020 10:40:27 +0300 Subject: [PATCH 02/14] chore: deprecate replaceable-components.state --- .../actions/replaceable-components.actions.ts | 3 +- .../states/replaceable-components.state.ts | 30 ++++++------------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/actions/replaceable-components.actions.ts b/npm/ng-packs/packages/core/src/lib/actions/replaceable-components.actions.ts index 8df6a384ad..a800ab858a 100644 --- a/npm/ng-packs/packages/core/src/lib/actions/replaceable-components.actions.ts +++ b/npm/ng-packs/packages/core/src/lib/actions/replaceable-components.actions.ts @@ -1,7 +1,8 @@ import { ReplaceableComponents } from '../models/replaceable-components'; +// tslint:disable: max-line-length /** - * @see usage: https://github.com/abpframework/abp/pull/2522#issue-358333183 + * @deprecated To be deleted in v4.0. Use ReplaceableComponentsService instead. See the doc (https://docs.abp.io/en/abp/latest/UI/Angular/Component-Replacement) */ export class AddReplaceableComponent { static readonly type = '[ReplaceableComponents] Add'; diff --git a/npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts b/npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts index 82096c5472..e5caa9f95b 100644 --- a/npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts +++ b/npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts @@ -1,11 +1,14 @@ -import { Injectable, NgZone } from '@angular/core'; -import { Router } from '@angular/router'; +import { Injectable } from '@angular/core'; import { Action, createSelector, Selector, State, StateContext } from '@ngxs/store'; import snq from 'snq'; import { AddReplaceableComponent } from '../actions/replaceable-components.actions'; import { ReplaceableComponents } from '../models/replaceable-components'; -import { noop } from '../utils/common-utils'; +import { ReplaceableComponentsService } from '../services/replaceable-components.service'; +// tslint:disable: max-line-length +/** + * @deprecated To be deleted in v4.0. Use ReplaceableComponentsService instead. See the doc (https://docs.abp.io/en/abp/latest/UI/Angular/Component-Replacement) + */ @State({ name: 'ReplaceableComponentsState', defaults: { replaceableComponents: [] } as ReplaceableComponents.State, @@ -30,23 +33,7 @@ export class ReplaceableComponentsState { return selector; } - constructor(private ngZone: NgZone, private router: Router) {} - - // TODO: Create a shared service for route reload and more - private reloadRoute() { - const { shouldReuseRoute } = this.router.routeReuseStrategy; - const setRouteReuse = (reuse: typeof shouldReuseRoute) => { - this.router.routeReuseStrategy.shouldReuseRoute = reuse; - }; - - setRouteReuse(() => false); - this.router.navigated = false; - - this.ngZone.run(async () => { - await this.router.navigateByUrl(this.router.url).catch(noop); - setRouteReuse(shouldReuseRoute); - }); - } + constructor(private service: ReplaceableComponentsService) {} @Action(AddReplaceableComponent) replaceableComponentsAction( @@ -69,6 +56,7 @@ export class ReplaceableComponentsState { replaceableComponents, }); - if (reload) this.reloadRoute(); + console.log(this.service); + this.service.add(payload, reload); } } From 7e7d86a745343c2e9c377a1c1e3752a45776c6ed Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 8 Sep 2020 10:42:07 +0300 Subject: [PATCH 03/14] feat: implement the new service to project --- .../components/dynamic-layout.component.ts | 9 ++- .../replaceable-route-container.component.ts | 9 ++- .../replaceable-template.directive.ts | 9 ++- .../tests/dynamic-layout.component.spec.ts | 63 +++++++++---------- .../src/lib/providers/styles.provider.ts | 39 ++++++------ 5 files changed, 61 insertions(+), 68 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts index c47b3c02fd..3d6870f577 100644 --- a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts +++ b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts @@ -1,13 +1,12 @@ import { Component, Injector, Optional, SkipSelf, Type } from '@angular/core'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; -import { Store } from '@ngxs/store'; import { eLayoutType } from '../enums/common'; import { ABP } from '../models'; import { ReplaceableComponents } from '../models/replaceable-components'; import { LocalizationService } from '../services/localization.service'; +import { ReplaceableComponentsService } from '../services/replaceable-components.service'; import { RoutesService } from '../services/routes.service'; import { SubscriptionService } from '../services/subscription.service'; -import { ReplaceableComponentsState } from '../states/replaceable-components.state'; import { findRoute, getRoutePath } from '../utils/route-utils'; import { TreeNode } from '../utils/tree-utils'; @@ -37,7 +36,7 @@ export class DynamicLayoutComponent { constructor( injector: Injector, private localizationService: LocalizationService, - private store: Store, + private replaceableComponents: ReplaceableComponentsService, private subscription: SubscriptionService, @Optional() @SkipSelf() dynamicLayoutComponent: DynamicLayoutComponent, ) { @@ -67,7 +66,7 @@ export class DynamicLayoutComponent { if (!expectedLayout) expectedLayout = eLayoutType.empty; const key = this.layouts.get(expectedLayout); - this.layout = this.getComponent(key).component; + this.layout = this.getComponent(key)?.component; } }); @@ -82,6 +81,6 @@ export class DynamicLayoutComponent { } private getComponent(key: string): ReplaceableComponents.ReplaceableComponent { - return this.store.selectSnapshot(ReplaceableComponentsState.getComponent(key)); + return this.replaceableComponents.get(key); } } diff --git a/npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts b/npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts index 04c596d398..6c0dabd511 100644 --- a/npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts +++ b/npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts @@ -1,10 +1,9 @@ import { Component, OnInit, Type } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngxs/store'; import { distinctUntilChanged } from 'rxjs/operators'; import { ReplaceableComponents } from '../models/replaceable-components'; +import { ReplaceableComponentsService } from '../services/replaceable-components.service'; import { SubscriptionService } from '../services/subscription.service'; -import { ReplaceableComponentsState } from '../states/replaceable-components.state'; @Component({ selector: 'abp-replaceable-route-container', @@ -22,7 +21,7 @@ export class ReplaceableRouteContainerComponent implements OnInit { constructor( private route: ActivatedRoute, - private store: Store, + private replaceableComponents: ReplaceableComponentsService, private subscription: SubscriptionService, ) {} @@ -31,8 +30,8 @@ export class ReplaceableRouteContainerComponent implements OnInit { this.componentKey = (this.route.snapshot.data .replaceableComponent as ReplaceableComponents.RouteData).key; - const component$ = this.store - .select(ReplaceableComponentsState.getComponent(this.componentKey)) + const component$ = this.replaceableComponents + .get$(this.componentKey) .pipe(distinctUntilChanged()); this.subscription.addOne( diff --git a/npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts index fd9051c64e..489d1afabc 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts @@ -10,15 +10,14 @@ import { Type, ViewContainerRef, } from '@angular/core'; -import { Store } from '@ngxs/store'; import compare from 'just-compare'; import { Subscription } from 'rxjs'; import { filter } from 'rxjs/operators'; import snq from 'snq'; import { ABP } from '../models/common'; import { ReplaceableComponents } from '../models/replaceable-components'; +import { ReplaceableComponentsService } from '../services/replaceable-components.service'; import { SubscriptionService } from '../services/subscription.service'; -import { ReplaceableComponentsState } from '../states/replaceable-components.state'; @Directive({ selector: '[abpReplaceableTemplate]', providers: [SubscriptionService] }) export class ReplaceableTemplateDirective implements OnInit, OnChanges { @@ -45,7 +44,7 @@ export class ReplaceableTemplateDirective implements OnInit, OnChanges { private templateRef: TemplateRef, private cfRes: ComponentFactoryResolver, private vcRef: ViewContainerRef, - private store: Store, + private replaceableComponents: ReplaceableComponentsService, private subscription: SubscriptionService, ) { this.context = { @@ -58,8 +57,8 @@ export class ReplaceableTemplateDirective implements OnInit, OnChanges { } ngOnInit() { - const component$ = this.store - .select(ReplaceableComponentsState.getComponent(this.data.componentKey)) + const component$ = this.replaceableComponents + .get$(this.data.componentKey) .pipe( filter( (res = {} as ReplaceableComponents.ReplaceableComponent) => diff --git a/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts index 4d5f53a9ba..43ad6f87b1 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts @@ -7,7 +7,11 @@ import { NEVER } from 'rxjs'; import { DynamicLayoutComponent, RouterOutletComponent } from '../components'; import { eLayoutType } from '../enums/common'; import { ABP } from '../models'; -import { ApplicationConfigurationService, RoutesService } from '../services'; +import { + ApplicationConfigurationService, + RoutesService, + ReplaceableComponentsService, +} from '../services'; import { ReplaceableComponentsState } from '../states'; @Component({ @@ -78,33 +82,7 @@ const routes: ABP.Route[] = [ }, ]; -const storeData = { - ReplaceableComponentsState: { - replaceableComponents: [ - { - key: 'Theme.ApplicationLayoutComponent', - component: DummyApplicationLayoutComponent, - }, - { - key: 'Theme.AccountLayoutComponent', - component: DummyAccountLayoutComponent, - }, - { - key: 'Theme.EmptyLayoutComponent', - component: DummyEmptyLayoutComponent, - }, - ], - }, -}; - describe('DynamicLayoutComponent', () => { - const mockActions: Actions = NEVER; - const mockStore = ({ - selectSnapshot() { - return true; - }, - } as unknown) as Store; - const createComponent = createRoutingFactory({ component: RouterOutletComponent, stubsEnabled: false, @@ -113,10 +91,16 @@ describe('DynamicLayoutComponent', () => { providers: [ { provide: RoutesService, - useFactory: () => new RoutesService(mockActions, mockStore), + useFactory: () => + new RoutesService(NEVER, ({ + selectSnapshot() { + return true; + }, + } as unknown) as Store), }, + ReplaceableComponentsService, ], - imports: [RouterModule, DummyLayoutModule, NgxsModule.forRoot([ReplaceableComponentsState])], + imports: [RouterModule, DummyLayoutModule, NgxsModule.forRoot()], routes: [ { path: '', component: RouterOutletComponent }, { @@ -163,15 +147,26 @@ describe('DynamicLayoutComponent', () => { }); let spectator: SpectatorRouting; - let store: Store; + let replaceableComponents: ReplaceableComponentsService; beforeEach(async () => { spectator = createComponent(); - store = spectator.inject(Store); + replaceableComponents = spectator.inject(ReplaceableComponentsService); const routesService = spectator.inject(RoutesService); routesService.add(routes); - store.reset(storeData); + replaceableComponents.add({ + key: 'Theme.ApplicationLayoutComponent', + component: DummyApplicationLayoutComponent, + }); + replaceableComponents.add({ + key: 'Theme.AccountLayoutComponent', + component: DummyAccountLayoutComponent, + }); + replaceableComponents.add({ + key: 'Theme.EmptyLayoutComponent', + component: DummyEmptyLayoutComponent, + }); }); it('should handle application layout from parent abp route and display it', async () => { @@ -204,8 +199,8 @@ describe('DynamicLayoutComponent', () => { }); it('should not display any layout when layouts are empty', async () => { - store.reset({ ...storeData, ReplaceableComponentsState: {} }); - + const spy = jest.spyOn(replaceableComponents, 'get'); + spy.mockReturnValue(null); spectator.detectChanges(); spectator.router.navigateByUrl('/withoutLayout'); diff --git a/npm/ng-packs/packages/theme-basic/src/lib/providers/styles.provider.ts b/npm/ng-packs/packages/theme-basic/src/lib/providers/styles.provider.ts index ab6ea9cd1e..b823503912 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/providers/styles.provider.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/providers/styles.provider.ts @@ -1,4 +1,4 @@ -import { AddReplaceableComponent, CONTENT_STRATEGY, DomInsertionService } from '@abp/ng.core'; +import { ReplaceableComponentsService, CONTENT_STRATEGY, DomInsertionService } from '@abp/ng.core'; import { APP_INITIALIZER } from '@angular/core'; import { Store } from '@ngxs/store'; import { AccountLayoutComponent } from '../components/account-layout/account-layout.component'; @@ -11,32 +11,33 @@ export const BASIC_THEME_STYLES_PROVIDERS = [ { provide: APP_INITIALIZER, useFactory: configureStyles, - deps: [DomInsertionService, Store], + deps: [DomInsertionService, ReplaceableComponentsService], multi: true, }, ]; -export function configureStyles(domInsertion: DomInsertionService, store: Store) { +export function configureStyles( + domInsertion: DomInsertionService, + replaceableComponents: ReplaceableComponentsService, +) { return () => { domInsertion.insertContent(CONTENT_STRATEGY.AppendStyleToHead(styles)); - initLayouts(store); + initLayouts(replaceableComponents); }; } -function initLayouts(store: Store) { - store.dispatch([ - new AddReplaceableComponent({ - key: eThemeBasicComponents.ApplicationLayout, - component: ApplicationLayoutComponent, - }), - new AddReplaceableComponent({ - key: eThemeBasicComponents.AccountLayout, - component: AccountLayoutComponent, - }), - new AddReplaceableComponent({ - key: eThemeBasicComponents.EmptyLayout, - component: EmptyLayoutComponent, - }), - ]); +function initLayouts(replaceableComponents: ReplaceableComponentsService) { + replaceableComponents.add({ + key: eThemeBasicComponents.ApplicationLayout, + component: ApplicationLayoutComponent, + }); + replaceableComponents.add({ + key: eThemeBasicComponents.AccountLayout, + component: AccountLayoutComponent, + }); + replaceableComponents.add({ + key: eThemeBasicComponents.EmptyLayout, + component: EmptyLayoutComponent, + }); } From 2104c86eab18ce32a0f74ecd6d3356f4d21e9c3b Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 8 Sep 2020 11:07:37 +0300 Subject: [PATCH 04/14] chore: remove console.log --- .../packages/core/src/lib/states/replaceable-components.state.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts b/npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts index e5caa9f95b..61a5fef5f6 100644 --- a/npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts +++ b/npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts @@ -56,7 +56,6 @@ export class ReplaceableComponentsState { replaceableComponents, }); - console.log(this.service); this.service.add(payload, reload); } } From 89df9fdde0a3f5a33ae6c4c01001ad4b4469c42f Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 8 Sep 2020 12:05:54 +0300 Subject: [PATCH 05/14] test: fix testing errors --- ...laceable-route-container.component.spec.ts | 18 +++++++-------- .../replaceable-template.directive.spec.ts | 22 +++++++++++-------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts index f5874bca46..16973c17c8 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts @@ -5,6 +5,7 @@ import { Store } from '@ngxs/store'; import { of, Subject, BehaviorSubject } from 'rxjs'; import { ReplaceableRouteContainerComponent } from '../components/replaceable-route-container.component'; import { ReplaceableComponentsState } from '../states'; +import { ReplaceableComponentsService } from '../services/replaceable-components.service'; @Component({ selector: 'abp-external-component', @@ -30,16 +31,15 @@ const activatedRouteMock = { }; describe('ReplaceableRouteContainerComponent', () => { - const selectResponse = new BehaviorSubject(undefined); - const mockSelect = jest.fn(() => selectResponse); - let spectator: SpectatorHost; + const get$Res = new BehaviorSubject(undefined); + const replaceableComponents = spectator.inject(ReplaceableComponentsService); + const spy = jest.spyOn(replaceableComponents, 'get$'); + spy.mockReturnValue(get$Res as any); + const createHost = createHostFactory({ component: ReplaceableRouteContainerComponent, - providers: [ - { provide: ActivatedRoute, useValue: activatedRouteMock }, - { provide: Store, useValue: { select: mockSelect } }, - ], + providers: [{ provide: ActivatedRoute, useValue: activatedRouteMock }], declarations: [ExternalComponent, DefaultComponent], entryComponents: [DefaultComponent, ExternalComponent], }); @@ -55,11 +55,11 @@ describe('ReplaceableRouteContainerComponent', () => { }); it("should display the external component if it's available in store.", () => { - selectResponse.next({ component: ExternalComponent }); + get$Res.next({ component: ExternalComponent }); spectator.detectChanges(); expect(spectator.query('p')).toHaveText('external'); - selectResponse.next({ component: null }); + get$Res.next({ component: null }); spectator.detectChanges(); expect(spectator.query('p')).toHaveText('default'); }); diff --git a/npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts index 613508f56b..2923dd473b 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts @@ -4,6 +4,8 @@ import { Store } from '@ngxs/store'; import { Subject } from 'rxjs'; import { ReplaceableTemplateDirective } from '../directives'; import { ReplaceableComponents } from '../models'; +import { Router } from '@angular/router'; +import { ReplaceableComponentsService } from '../services/replaceable-components.service'; @Component({ selector: 'abp-default-component', @@ -48,15 +50,17 @@ class ExternalComponent { } describe('ReplaceableTemplateDirective', () => { - const selectResponse = new Subject(); - const mockSelect = jest.fn(() => selectResponse); - let spectator: SpectatorDirective; + const get$Res = new Subject(); + + const replaceableComponents = spectator.inject(ReplaceableComponentsService); + const spy = jest.spyOn(replaceableComponents, 'get$'); + spy.mockReturnValue(get$Res as any); const createDirective = createDirectiveFactory({ directive: ReplaceableTemplateDirective, - providers: [{ provide: Store, useValue: { select: mockSelect } }], declarations: [DefaultComponent, ExternalComponent], entryComponents: [ExternalComponent], + mocks: [Router], }); describe('without external component', () => { @@ -72,7 +76,7 @@ describe('ReplaceableTemplateDirective', () => { `, { hostProps: { oneWay: { label: 'Test' }, twoWay: false, twoWayChange, someOutput } }, ); - selectResponse.next(undefined); + get$Res.next(undefined); const component = spectator.query(DefaultComponent); spectator.directive.context.initTemplate(component); spectator.detectChanges(); @@ -114,7 +118,7 @@ describe('ReplaceableTemplateDirective', () => { `, { hostProps: { oneWay: { label: 'Test' }, twoWay: false, twoWayChange, someOutput } }, ); - selectResponse.next({ component: ExternalComponent, key: 'TestModule.TestComponent' }); + get$Res.next({ component: ExternalComponent, key: 'TestModule.TestComponent' }); }); afterEach(() => twoWayChange.mockClear()); @@ -150,7 +154,7 @@ describe('ReplaceableTemplateDirective', () => { const externalComponent = spectator.query(ExternalComponent); spectator.setHostInput({ oneWay: 'test' }); externalComponent.data.inputs.twoWay = true; - selectResponse.next({ component: null, key: 'TestModule.TestComponent' }); + get$Res.next({ component: null, key: 'TestModule.TestComponent' }); spectator.detectChanges(); const component = spectator.query(DefaultComponent); spectator.directive.context.initTemplate(component); @@ -161,14 +165,14 @@ describe('ReplaceableTemplateDirective', () => { }); it('should reset default component subscriptions', () => { - selectResponse.next({ component: null, key: 'TestModule.TestComponent' }); + get$Res.next({ component: null, key: 'TestModule.TestComponent' }); const component = spectator.query(DefaultComponent); spectator.directive.context.initTemplate(component); spectator.detectChanges(); const unsubscribe = jest.fn(() => {}); spectator.directive.defaultComponentSubscriptions.twoWayChange.unsubscribe = unsubscribe; - selectResponse.next({ component: ExternalComponent, key: 'TestModule.TestComponent' }); + get$Res.next({ component: ExternalComponent, key: 'TestModule.TestComponent' }); expect(unsubscribe).toHaveBeenCalled(); }); }); From 431d02f177153c79ae6330a45c8c27de3d95a1fa Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 8 Sep 2020 14:26:45 +0300 Subject: [PATCH 06/14] chore: add deprecation message logger to replaceable-components.state --- .../lib/states/replaceable-components.state.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts b/npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts index 61a5fef5f6..8b861f144e 100644 --- a/npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts +++ b/npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts @@ -1,10 +1,19 @@ -import { Injectable } from '@angular/core'; +import { Injectable, isDevMode } from '@angular/core'; import { Action, createSelector, Selector, State, StateContext } from '@ngxs/store'; import snq from 'snq'; import { AddReplaceableComponent } from '../actions/replaceable-components.actions'; import { ReplaceableComponents } from '../models/replaceable-components'; import { ReplaceableComponentsService } from '../services/replaceable-components.service'; +function logDeprecationMsg() { + if (isDevMode()) { + console.warn(` + ReplacableComponentsState has been deprecated. Use ReplaceableComponentsService instead. + See the doc https://docs.abp.io/en/abp/latest/UI/Angular/Component-Replacement + `); + } +} + // tslint:disable: max-line-length /** * @deprecated To be deleted in v4.0. Use ReplaceableComponentsService instead. See the doc (https://docs.abp.io/en/abp/latest/UI/Angular/Component-Replacement) @@ -19,6 +28,7 @@ export class ReplaceableComponentsState { static getAll({ replaceableComponents, }: ReplaceableComponents.State): ReplaceableComponents.ReplaceableComponent[] { + logDeprecationMsg(); return replaceableComponents || []; } @@ -26,6 +36,7 @@ export class ReplaceableComponentsState { const selector = createSelector( [ReplaceableComponentsState], (state: ReplaceableComponents.State): ReplaceableComponents.ReplaceableComponent => { + logDeprecationMsg(); return snq(() => state.replaceableComponents.find(component => component.key === key)); }, ); @@ -40,6 +51,8 @@ export class ReplaceableComponentsState { { getState, patchState }: StateContext, { payload, reload }: AddReplaceableComponent, ) { + logDeprecationMsg(); + let { replaceableComponents } = getState(); const index = snq( From 7653b020014147ea563d38dc44c8746caf829cb4 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 9 Sep 2020 10:29:52 +0300 Subject: [PATCH 07/14] feat: implement internal store to ReplaceableComponentsService --- .../replaceable-components.service.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts index 418e608c49..3f2b2cd17c 100644 --- a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts @@ -4,20 +4,27 @@ import { ReplaceableComponents } from '../models/replaceable-components'; import { BehaviorSubject, Observable } from 'rxjs'; import { noop } from '../utils/common-utils'; import { map, filter } from 'rxjs/operators'; +import { InternalStore } from '../utils/internal-store-utils'; @Injectable({ providedIn: 'root' }) export class ReplaceableComponentsService { - private components$ = new BehaviorSubject([]); + private state: InternalStore; get replaceableComponents$(): Observable { - return this.components$.asObservable(); + return this.state.sliceState(state => state); } get replaceableComponents(): ReplaceableComponents.ReplaceableComponent[] { - return this.components$.value; + return this.state.state; } - constructor(private ngZone: NgZone, private router: Router) {} + get onUpdate$(): Observable { + return this.state.sliceUpdate(state => state); + } + + constructor(private ngZone: NgZone, private router: Router) { + this.state = new InternalStore([]); + } // TODO: Create a shared service for route reload and more private reloadRoute() { @@ -36,7 +43,7 @@ export class ReplaceableComponentsService { } add(replaceableComponent: ReplaceableComponents.ReplaceableComponent, reload?: boolean): void { - let replaceableComponents = this.components$.value; + let replaceableComponents = this.state.state; const index = replaceableComponents.findIndex( component => component.key === replaceableComponent.key, @@ -48,7 +55,7 @@ export class ReplaceableComponentsService { replaceableComponents = [...replaceableComponents, replaceableComponent]; } - this.components$.next(replaceableComponents); + this.state.patch(replaceableComponents); if (reload) this.reloadRoute(); } From 1661d58a4aa2dac5e4263e24504f37ee8e1ec9ba Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 9 Sep 2020 11:16:03 +0300 Subject: [PATCH 08/14] test: fix some errors --- ...eplaceable-route-container.component.spec.ts | 17 ++++++++--------- .../replaceable-template.directive.spec.ts | 11 +++++------ 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts index 16973c17c8..9b8b62ef46 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts @@ -1,10 +1,8 @@ -import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Store } from '@ngxs/store'; -import { of, Subject, BehaviorSubject } from 'rxjs'; +import { ActivatedRoute, Router } from '@angular/router'; +import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; +import { BehaviorSubject } from 'rxjs'; import { ReplaceableRouteContainerComponent } from '../components/replaceable-route-container.component'; -import { ReplaceableComponentsState } from '../states'; import { ReplaceableComponentsService } from '../services/replaceable-components.service'; @Component({ @@ -33,15 +31,16 @@ const activatedRouteMock = { describe('ReplaceableRouteContainerComponent', () => { let spectator: SpectatorHost; const get$Res = new BehaviorSubject(undefined); - const replaceableComponents = spectator.inject(ReplaceableComponentsService); - const spy = jest.spyOn(replaceableComponents, 'get$'); - spy.mockReturnValue(get$Res as any); const createHost = createHostFactory({ component: ReplaceableRouteContainerComponent, - providers: [{ provide: ActivatedRoute, useValue: activatedRouteMock }], + providers: [ + { provide: ActivatedRoute, useValue: activatedRouteMock }, + { provide: ReplaceableComponentsService, useValue: { get$: () => get$Res } }, + ], declarations: [ExternalComponent, DefaultComponent], entryComponents: [DefaultComponent, ExternalComponent], + mocks: [Router], }); beforeEach(() => { diff --git a/npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts index 2923dd473b..2c1432e525 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Inject, Input, OnInit, Optional, Output } from '@angular/core'; import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/jest'; import { Store } from '@ngxs/store'; -import { Subject } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; import { ReplaceableTemplateDirective } from '../directives'; import { ReplaceableComponents } from '../models'; import { Router } from '@angular/router'; @@ -51,16 +51,14 @@ class ExternalComponent { describe('ReplaceableTemplateDirective', () => { let spectator: SpectatorDirective; - const get$Res = new Subject(); + const get$Res = new BehaviorSubject(undefined); - const replaceableComponents = spectator.inject(ReplaceableComponentsService); - const spy = jest.spyOn(replaceableComponents, 'get$'); - spy.mockReturnValue(get$Res as any); const createDirective = createDirectiveFactory({ directive: ReplaceableTemplateDirective, declarations: [DefaultComponent, ExternalComponent], entryComponents: [ExternalComponent], mocks: [Router], + providers: [{ provide: ReplaceableComponentsService, useValue: { get$: () => get$Res } }], }); describe('without external component', () => { @@ -76,7 +74,7 @@ describe('ReplaceableTemplateDirective', () => { `, { hostProps: { oneWay: { label: 'Test' }, twoWay: false, twoWayChange, someOutput } }, ); - get$Res.next(undefined); + const component = spectator.query(DefaultComponent); spectator.directive.context.initTemplate(component); spectator.detectChanges(); @@ -118,6 +116,7 @@ describe('ReplaceableTemplateDirective', () => { `, { hostProps: { oneWay: { label: 'Test' }, twoWay: false, twoWayChange, someOutput } }, ); + get$Res.next({ component: ExternalComponent, key: 'TestModule.TestComponent' }); }); From 1246a419926671ad03bd71cd79c449533a6cd53b Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 9 Sep 2020 11:51:50 +0300 Subject: [PATCH 09/14] refactor: change a variable name --- .../lib/services/replaceable-components.service.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts index 3f2b2cd17c..486f1bcd44 100644 --- a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts @@ -8,22 +8,22 @@ import { InternalStore } from '../utils/internal-store-utils'; @Injectable({ providedIn: 'root' }) export class ReplaceableComponentsService { - private state: InternalStore; + private store: InternalStore; get replaceableComponents$(): Observable { - return this.state.sliceState(state => state); + return this.store.sliceState(state => state); } get replaceableComponents(): ReplaceableComponents.ReplaceableComponent[] { - return this.state.state; + return this.store.state; } get onUpdate$(): Observable { - return this.state.sliceUpdate(state => state); + return this.store.sliceUpdate(state => state); } constructor(private ngZone: NgZone, private router: Router) { - this.state = new InternalStore([]); + this.store = new InternalStore([]); } // TODO: Create a shared service for route reload and more @@ -43,7 +43,7 @@ export class ReplaceableComponentsService { } add(replaceableComponent: ReplaceableComponents.ReplaceableComponent, reload?: boolean): void { - let replaceableComponents = this.state.state; + let replaceableComponents = this.store.state; const index = replaceableComponents.findIndex( component => component.key === replaceableComponent.key, @@ -55,7 +55,7 @@ export class ReplaceableComponentsService { replaceableComponents = [...replaceableComponents, replaceableComponent]; } - this.state.patch(replaceableComponents); + this.store.patch(replaceableComponents); if (reload) this.reloadRoute(); } From 0c5fbee1c38a58cebd82acb7e21b059b39f0d3ba Mon Sep 17 00:00:00 2001 From: Mehmet Erim <34455572+mehmet-erim@users.noreply.github.com> Date: Wed, 9 Sep 2020 12:40:17 +0300 Subject: [PATCH 10/14] Update npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Levent Arman Özak --- .../core/src/lib/services/replaceable-components.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts index 486f1bcd44..fd04c1c511 100644 --- a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts @@ -43,7 +43,7 @@ export class ReplaceableComponentsService { } add(replaceableComponent: ReplaceableComponents.ReplaceableComponent, reload?: boolean): void { - let replaceableComponents = this.store.state; + const replaceableComponents = [...this.store.state]; const index = replaceableComponents.findIndex( component => component.key === replaceableComponent.key, @@ -52,7 +52,7 @@ export class ReplaceableComponentsService { if (index > -1) { replaceableComponents[index] = replaceableComponent; } else { - replaceableComponents = [...replaceableComponents, replaceableComponent]; + replaceableComponents.push(replaceableComponent); } this.store.patch(replaceableComponents); From 8edcac597a412ea9de38544801d2a872fd644d1b Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 9 Sep 2020 12:46:42 +0300 Subject: [PATCH 11/14] refactor: move reloadRoute function to route-utils.ts --- .../services/replaceable-components.service.ts | 17 ++--------------- .../packages/core/src/lib/utils/route-utils.ts | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts index fd04c1c511..7dfd1e5062 100644 --- a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts @@ -5,6 +5,7 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { noop } from '../utils/common-utils'; import { map, filter } from 'rxjs/operators'; import { InternalStore } from '../utils/internal-store-utils'; +import { reloadRoute } from '../utils/route-utils'; @Injectable({ providedIn: 'root' }) export class ReplaceableComponentsService { @@ -27,20 +28,6 @@ export class ReplaceableComponentsService { } // TODO: Create a shared service for route reload and more - private reloadRoute() { - const { shouldReuseRoute } = this.router.routeReuseStrategy; - const setRouteReuse = (reuse: typeof shouldReuseRoute) => { - this.router.routeReuseStrategy.shouldReuseRoute = reuse; - }; - - setRouteReuse(() => false); - this.router.navigated = false; - - this.ngZone.run(async () => { - await this.router.navigateByUrl(this.router.url).catch(noop); - setRouteReuse(shouldReuseRoute); - }); - } add(replaceableComponent: ReplaceableComponents.ReplaceableComponent, reload?: boolean): void { const replaceableComponents = [...this.store.state]; @@ -57,7 +44,7 @@ export class ReplaceableComponentsService { this.store.patch(replaceableComponents); - if (reload) this.reloadRoute(); + if (reload) reloadRoute(this.router, this.ngZone); } get(replaceableComponentKey: string): ReplaceableComponents.ReplaceableComponent { diff --git a/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts index a749090695..388e76cbf8 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts @@ -2,6 +2,8 @@ import { PRIMARY_OUTLET, Router, UrlSegmentGroup } from '@angular/router'; import { ABP } from '../models/common'; import { RoutesService } from '../services/routes.service'; import { TreeNode } from './tree-utils'; +import { noop } from './common-utils'; +import { NgZone } from '@angular/core'; export function findRoute(routes: RoutesService, path: string): TreeNode { const node = routes.find(route => route.path === path); @@ -23,3 +25,18 @@ export function getRoutePath(router: Router, url = router.url) { return '/' + (primaryGroup || emptyGroup).segments.map(({ path }) => path).join('/'); } + +export function reloadRoute(router: Router, ngZone: NgZone) { + const { shouldReuseRoute } = router.routeReuseStrategy; + const setRouteReuse = (reuse: typeof shouldReuseRoute) => { + router.routeReuseStrategy.shouldReuseRoute = reuse; + }; + + setRouteReuse(() => false); + router.navigated = false; + + ngZone.run(async () => { + await router.navigateByUrl(router.url).catch(noop); + setRouteReuse(shouldReuseRoute); + }); +} From f34057593db2280ed5dd705a7ee69793160fe435 Mon Sep 17 00:00:00 2001 From: Mehmet Erim <34455572+mehmet-erim@users.noreply.github.com> Date: Wed, 9 Sep 2020 12:53:39 +0300 Subject: [PATCH 12/14] Update npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts Co-authored-by: Bunyamin Coskuner --- .../core/src/lib/services/replaceable-components.service.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts index 7dfd1e5062..674db83aea 100644 --- a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts @@ -27,8 +27,6 @@ export class ReplaceableComponentsService { this.store = new InternalStore([]); } - // TODO: Create a shared service for route reload and more - add(replaceableComponent: ReplaceableComponents.ReplaceableComponent, reload?: boolean): void { const replaceableComponents = [...this.store.state]; From 8bbbb24507bb0cbfb909683f3b444d3f1195bcf8 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 9 Sep 2020 13:04:31 +0300 Subject: [PATCH 13/14] docs: add ReplaceableComponentsService example to Component-Replacement.md --- docs/en/UI/Angular/Component-Replacement.md | 77 ++++++++------------- 1 file changed, 28 insertions(+), 49 deletions(-) diff --git a/docs/en/UI/Angular/Component-Replacement.md b/docs/en/UI/Angular/Component-Replacement.md index fd34fcbae7..d79a67829c 100644 --- a/docs/en/UI/Angular/Component-Replacement.md +++ b/docs/en/UI/Angular/Component-Replacement.md @@ -8,27 +8,22 @@ The reason that you **can replace** but **cannot customize** default ABP compone Create a new component that you want to use instead of an ABP component. Add that component to `declarations` and `entryComponents` in the `AppModule`. -Then, open the `app.component.ts` and dispatch the `AddReplaceableComponent` action to replace your component with an ABP component as shown below: +Then, open the `app.component.ts` and execute the `add` method of `ReplaceableComponentsService` to replace your component with an ABP component as shown below: ```js -import { AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent action +import { ReplaceableComponentsService } from '@abp/ng.core'; // imported ReplaceableComponentsService import { eIdentityComponents } from '@abp/ng.identity'; // imported eIdentityComponents enum -import { Store } from '@ngxs/store'; // imported Store //... @Component(/* component metadata */) export class AppComponent { constructor( - private store: Store // injected Store - ) - { - // dispatched the AddReplaceableComponent action - this.store.dispatch( - new AddReplaceableComponent({ - component: YourNewRoleComponent, - key: eIdentityComponents.Roles, - }), - ); + private replaceableComponents: ReplaceableComponentsService, // injected the service + ) { + this.replaceableComponents.add({ + component: YourNewRoleComponent, + key: eIdentityComponents.Roles, + }); } } ``` @@ -59,28 +54,24 @@ Add the following code in your layout template (`my-layout.component.html`) wher Open `app.component.ts` in `src/app` folder and modify it as shown below: ```js -import { AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent +import { ReplaceableComponentsService } from '@abp/ng.core'; // imported ReplaceableComponentsService import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents enum for component keys -import { Store } from '@ngxs/store'; // imported Store import { MyApplicationLayoutComponent } from './my-application-layout/my-application-layout.component'; // imported MyApplicationLayoutComponent @Component(/* component metadata */) export class AppComponent { constructor( - private store: Store, // injected Store + private replaceableComponents: ReplaceableComponentsService, // injected the service ) { - // dispatched the AddReplaceableComponent action - this.store.dispatch( - new AddReplaceableComponent({ - component: MyApplicationLayoutComponent, - key: eThemeBasicComponents.ApplicationLayout, - }), - ); + this.replaceableComponents.add({ + component: MyApplicationLayoutComponent, + key: eThemeBasicComponents.ApplicationLayout, + }); } } ``` -> If you like to replace a layout component at runtime (e.g: changing the layout by pressing a button), pass the second parameter of the AddReplaceableComponent action as true. DynamicLayoutComponent loads content using a router-outlet. When the second parameter of AddReplaceableComponent is true, the route will be refreshed, so use it with caution. Your component state will be gone and any initiation logic (including HTTP requests) will be repeated. +> If you like to replace a layout component at runtime (e.g: changing the layout by pressing a button), pass the second parameter of the `add` method of `ReplaceableComponentsService` as true. DynamicLayoutComponent loads content using a router-outlet. When the second parameter of the `add` method is true, the route will be refreshed, so use it with caution. Your component state will be gone and any initiation logic (including HTTP requests) will be repeated. ### Layout Components @@ -123,26 +114,22 @@ export class LogoComponent {} Open `app.component.ts` in `src/app` folder and modify it as shown below: ```js -import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent -import { Store } from '@ngxs/store'; // imported Store +import { ..., ReplaceableComponentsService } from '@abp/ng.core'; // imported ReplaceableComponentsService import { LogoComponent } from './logo/logo.component'; // imported NavItemsComponent import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents //... @Component(/* component metadata */) export class AppComponent implements OnInit { - constructor(..., private store: Store) {} // injected Store + constructor(..., private replaceableComponents: ReplaceableComponentsService) {} // injected ReplaceableComponentsService ngOnInit() { //... - // added dispatch - this.store.dispatch( - new AddReplaceableComponent({ + this.replaceableComponents.add({ component: LogoComponent, key: eThemeBasicComponents.Logo, - }), - ); + }); } } ``` @@ -166,7 +153,7 @@ yarn ng generate component routes --entryComponent Open the generated `routes.component.ts` in `src/app/routes` folder and replace its content with the following: ```js -import { ABP, ReplaceableComponents } from '@abp/ng.core'; +import { ABP } from '@abp/ng.core'; import { Component, HostBinding, @@ -309,26 +296,22 @@ Open the generated `routes.component.html` in `src/app/routes` folder and replac Open `app.component.ts` in `src/app` folder and modify it as shown below: ```js -import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent -import { Store } from '@ngxs/store'; // imported Store +import { ..., ReplaceableComponentsService } from '@abp/ng.core'; // imported ReplaceableComponentsService import { RoutesComponent } from './routes/routes.component'; // imported NavItemsComponent import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents //... @Component(/* component metadata */) export class AppComponent implements OnInit { - constructor(..., private store: Store) {} // injected Store + constructor(..., private replaceableComponents: ReplaceableComponentsService) {} // injected ReplaceableComponentsService ngOnInit() { //... - // added dispatch - this.store.dispatch( - new AddReplaceableComponent({ + this.replaceableComponents.add({ component: RoutesComponent, key: eThemeBasicComponents.Routes, - }), - ); + }); } } ``` @@ -511,26 +494,22 @@ Open the generated `nav-items.component.html` in `src/app/nav-items` folder and Open `app.component.ts` in `src/app` folder and modify it as shown below: ```js -import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent -import { Store } from '@ngxs/store'; // imported Store +import { ..., ReplaceableComponentsService } from '@abp/ng.core'; // imported ReplaceableComponentsService import { NavItemsComponent } from './nav-items/nav-items.component'; // imported NavItemsComponent import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents //... @Component(/* component metadata */) export class AppComponent implements OnInit { - constructor(..., private store: Store) {} // injected Store + constructor(..., private replaceableComponents: ReplaceableComponentsService) {} // injected ReplaceableComponentsService ngOnInit() { //... - // added dispatch - this.store.dispatch( - new AddReplaceableComponent({ + this.replaceableComponents.add({ component: NavItemsComponent, key: eThemeBasicComponents.NavItems, - }), - ); + }); } } ``` From c3be8dbdd5a77b7accf9c23a43cb7c1cf8f9c0c2 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 9 Sep 2020 13:05:11 +0300 Subject: [PATCH 14/14] docs: use ReplaceableComponentsService in permissions modal replacement modal --- .../Permission-Management-Component-Replacement.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/en/UI/Angular/Permission-Management-Component-Replacement.md b/docs/en/UI/Angular/Permission-Management-Component-Replacement.md index acdfffb948..9ae712cedd 100644 --- a/docs/en/UI/Angular/Permission-Management-Component-Replacement.md +++ b/docs/en/UI/Angular/Permission-Management-Component-Replacement.md @@ -473,24 +473,20 @@ Open the generated `permission-management.component.html` in `src/app/permission Open `app.component.ts` in `src/app` folder and modify it as shown below: ```js -import { AddReplaceableComponent } from '@abp/ng.core'; +import { ReplaceableComponentsService } from '@abp/ng.core'; import { ePermissionManagementComponents } from '@abp/ng.permission-management'; import { Component, OnInit } from '@angular/core'; -import { Store } from '@ngxs/store'; import { PermissionManagementComponent } from './permission-management/permission-management.component'; //... export class AppComponent implements OnInit { - constructor(private store: Store) {} // injected store + constructor(private replaceableComponents: ReplaceableComponentsService) {} // injected ReplaceableComponentsService ngOnInit() { - // added dispatching the AddReplaceableComponent action - this.store.dispatch( - new AddReplaceableComponent({ + this.replaceableComponents.add({ component: PermissionManagementComponent, key: ePermissionManagementComponents.PermissionManagement, - }) - ); + }); } } ```