# Component Replacement You can replace some ABP components with your custom components. The reason that you **can replace** but **cannot customize** default ABP components is disabling or changing a part of that component can cause problems. So we named those components as _Replaceable Components_. ## How to Replace a Component 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 execute the `add` method of `ReplaceableComponentsService` to replace your component with an ABP component as shown below: ```js import { ReplaceableComponentsService } from '@abp/ng.core'; // imported ReplaceableComponentsService import { eIdentityComponents } from '@abp/ng.identity'; // imported eIdentityComponents enum //... @Component(/* component metadata */) export class AppComponent { constructor( private replaceableComponents: ReplaceableComponentsService, // injected the service ) { this.replaceableComponents.add({ component: YourNewRoleComponent, key: eIdentityComponents.Roles, }); } } ``` ![Example Usage](./images/component-replacement.gif) ## How to Replace a Layout Each ABP theme module has 3 layouts named `ApplicationLayoutComponent`, `AccountLayoutComponent`, `EmptyLayoutComponent`. These layouts can be replaced the same way. > A layout component template should contain `` element. The example below describes how to replace the `ApplicationLayoutComponent`: Run the following command to generate a layout in `angular` folder: ```bash yarn ng generate component my-application-layout ``` Add the following code in your layout template (`my-application-layout.component.html`) where you want the page to be loaded. ```html ``` Open `app.component.ts` in `src/app` folder and modify it as shown below: ```js import { ReplaceableComponentsService } from '@abp/ng.core'; // imported ReplaceableComponentsService import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents enum for component keys import { MyApplicationLayoutComponent } from './my-application-layout/my-application-layout.component'; // imported MyApplicationLayoutComponent @Component(/* component metadata */) export class AppComponent { constructor( private replaceableComponents: ReplaceableComponentsService, // injected the service ) { 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 `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 ![Layout Components](./images/layout-components.png) #### How to Replace LogoComponent ![LogoComponent](./images/logo-component.png) Run the following command in `angular` folder to create a new component called `LogoComponent`. ```bash yarn ng generate component logo --inlineTemplate --inlineStyle ``` Open the generated `logo.component.ts` in `src/app/logo` folder and replace its content with the following: ```js import { Component } from '@angular/core'; @Component({ selector: 'app-logo', template: ` logo `, }) export class LogoComponent {} ``` Open `app.component.ts` in `src/app` folder and modify it as shown below: ```js import { ..., ReplaceableComponentsService } from '@abp/ng.core'; // imported ReplaceableComponentsService import { LogoComponent } from './logo/logo.component'; // imported LogoComponent import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents //... @Component(/* component metadata */) export class AppComponent implements OnInit { constructor(..., private replaceableComponents: ReplaceableComponentsService) {} // injected ReplaceableComponentsService ngOnInit() { //... this.replaceableComponents.add({ component: LogoComponent, key: eThemeBasicComponents.Logo, }); } } ``` The final UI looks like below: ![New logo](./images/replaced-logo-component.png) #### How to Replace RoutesComponent ![RoutesComponent](./images/routes-component.png) Run the following command in `angular` folder to create a new component called `RoutesComponent`. ```bash yarn ng generate component routes ``` Open the generated `routes.component.ts` in `src/app/routes` folder and replace its content with the following: ```js import { Component, HostBinding } from '@angular/core'; @Component({ selector: 'app-routes', templateUrl: 'routes.component.html', }) export class RoutesComponent { @HostBinding('class.mx-auto') marginAuto = true; get smallScreen() { return window.innerWidth < 992; } } ``` Import the `SharedModule` to the `imports` array of `AppModule`: ```js // app.module.ts import { SharedModule } from './shared/shared.module'; @NgModule({ imports: [ //... SharedModule ] )} ``` Open the generated `routes.component.html` in `src/app/routes` folder and replace its content with the following: ```html ``` Open `app.component.ts` in `src/app` folder and modify it as shown below: ```js import { ..., ReplaceableComponentsService } from '@abp/ng.core'; // imported ReplaceableComponentsService import { RoutesComponent } from './routes/routes.component'; // imported RoutesComponent import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents //... @Component(/* component metadata */) export class AppComponent implements OnInit { constructor(..., private replaceableComponents: ReplaceableComponentsService) {} // injected ReplaceableComponentsService ngOnInit() { //... this.replaceableComponents.add({ component: RoutesComponent, key: eThemeBasicComponents.Routes, }); } } ``` The final UI looks like below: ![New routes](./images/replaced-routes-component.png) #### How to Replace NavItemsComponent ![NavItemsComponent](./images/nav-items-component.png) Run the following command in `angular` folder to create a new component called `NavItemsComponent`. ```bash yarn ng generate component nav-items ``` Open the generated `nav-items.component.ts` in `src/app/nav-items` folder and replace the content with the following: ```js import { AuthService, ConfigStateService, CurrentUserDto, LanguageInfo, NAVIGATE_TO_MANAGE_PROFILE, SessionStateService, } from '@abp/ng.core'; import { Component, Inject } from '@angular/core'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import snq from 'snq'; @Component({ selector: 'app-nav-items', templateUrl: 'nav-items.component.html', }) export class NavItemsComponent { currentUser$: Observable = this.configState.getOne$('currentUser'); selectedTenant$ = this.sessionState.getTenant$(); languages$: Observable = this.configState.getDeep$('localization.languages'); get smallScreen(): boolean { return window.innerWidth < 992; } get defaultLanguage$(): Observable { return this.languages$.pipe( map( languages => snq( () => languages.find(lang => lang.cultureName === this.selectedLangCulture).displayName ), '' ) ); } get dropdownLanguages$(): Observable { return this.languages$.pipe( map( languages => snq(() => languages.filter(lang => lang.cultureName !== this.selectedLangCulture)), [] ) ); } get selectedLangCulture(): string { return this.sessionState.getLanguage(); } constructor( @Inject(NAVIGATE_TO_MANAGE_PROFILE) public navigateToManageProfile, private configState: ConfigStateService, private authService: AuthService, private sessionState: SessionStateService ) {} onChangeLang(cultureName: string) { this.sessionState.setLanguage(cultureName); } navigateToLogin() { this.authService.navigateToLogin(); } logout() { this.authService.logout().subscribe(); } } ``` Import the `SharedModule` to the `imports` array of `AppModule`: ```js // app.module.ts import { SharedModule } from './shared/shared.module'; @NgModule({ imports: [ //... SharedModule ] )} ``` Open the generated `nav-items.component.html` in `src/app/nav-items` folder and replace the content with the following: ```html ``` Open `app.component.ts` in `src/app` folder and modify it as shown below: ```js 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 replaceableComponents: ReplaceableComponentsService) {} // injected ReplaceableComponentsService ngOnInit() { //... this.replaceableComponents.add({ component: NavItemsComponent, key: eThemeBasicComponents.NavItems, }); } } ``` The final UI looks like below: ![New nav-items](./images/replaced-nav-items-component.png) ## See Also - [How Replaceable Components Work with Extensions](./How-Replaceable-Components-Work-with-Extensions.md) - [How to Replace PermissionManagementComponent](./Permission-Management-Component-Replacement.md)