# 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 dispatch the `AddReplaceableComponent` action to replace your component with an ABP component as shown below: ```js import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent action import { eIdentityComponents } from '@abp/ng.identity'; // imported eIdentityComponents enum import { Store } from '@ngxs/store'; // imported Store //... @Component(/* component metadata */) export class AppComponent implements OnInit { constructor(..., private store: Store) {} // injected Store ngOnInit() { // added dispatch this.store.dispatch( new AddReplaceableComponent({ 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 shared/my-application-layout --export --entryComponent # You don't need the --entryComponent option in Angular 9 ``` Add the following code in your layout template (`my-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 { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents enum for component keys import { MyApplicationLayoutComponent } from './shared/my-application-layout/my-application-layout.component'; // imported MyApplicationLayoutComponent import { Store } from '@ngxs/store'; // imported Store //... @Component(/* component metadata */) export class AppComponent implements OnInit { constructor(..., private store: Store) {} // injected Store ngOnInit() { // added dispatch this.store.dispatch( new AddReplaceableComponent({ component: MyApplicationLayoutComponent, key: eThemeBasicComponents.ApplicationLayout, }), ); //... } } ``` ### 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 --entryComponent # You don't need the --entryComponent option in Angular 9 ``` 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 { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent import { Store } from '@ngxs/store'; // imported Store 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 ngOnInit() { //... // added dispatch this.store.dispatch( new AddReplaceableComponent({ 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 --entryComponent # You don't need the --entryComponent option in Angular 9 ``` 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 { Component, HostBinding, Inject, Renderer2, TrackByFunction, AfterViewInit, } from '@angular/core'; import { fromEvent } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; @Component({ selector: 'app-routes', templateUrl: 'routes.component.html', }) export class RoutesComponent implements AfterViewInit { @HostBinding('class.mx-auto') marginAuto = true; smallScreen = window.innerWidth < 992; constructor(private renderer: Renderer2) {} ngAfterViewInit() { fromEvent(window, 'resize') .pipe(debounceTime(150)) .subscribe(() => { this.smallScreen = window.innerWidth < 992; }); } } ``` 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 { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent import { Store } from '@ngxs/store'; // imported Store 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 ngOnInit() { //... // added dispatch this.store.dispatch( new AddReplaceableComponent({ 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 --entryComponent # You don't need the --entryComponent option in Angular 9 ``` Open the generated `nav-items.component.ts` in `src/app/nav-items` folder and replace the content with the following: ```js import { ApplicationConfiguration, AuthService, ConfigState, SessionState, SetLanguage, } from '@abp/ng.core'; import { Component, AfterViewInit } from '@angular/core'; import { Navigate, RouterState } from '@ngxs/router-plugin'; import { Select, Store } from '@ngxs/store'; import { Observable, fromEvent } from 'rxjs'; import { map, debounceTime } from 'rxjs/operators'; import snq from 'snq'; @Component({ selector: 'app-nav-items', templateUrl: 'nav-items.component.html', }) export class NavItemsComponent implements AfterViewInit { @Select(ConfigState.getOne('currentUser')) currentUser$: Observable; @Select(ConfigState.getDeep('localization.languages')) languages$: Observable; smallScreen = 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.store.selectSnapshot(SessionState.getLanguage); } constructor(private store: Store, private authService: AuthService) {} ngAfterViewInit() { fromEvent(window, 'resize') .pipe(debounceTime(150)) .subscribe(() => { this.smallScreen = window.innerWidth < 992; }); } onChangeLang(cultureName: string) { this.store.dispatch(new SetLanguage(cultureName)); } logout() { this.authService.logout().subscribe(() => { this.store.dispatch( new Navigate(['/'], null, { state: { redirectUrl: this.store.selectSnapshot(RouterState).state.url }, }), ); }); } } ``` 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 { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent import { Store } from '@ngxs/store'; // imported Store 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 ngOnInit() { //... // added dispatch this.store.dispatch( new AddReplaceableComponent({ component: NavItemsComponent, key: eThemeBasicComponents.NavItems, }), ); } } ``` The final UI looks like below: ![New nav-items](./images/replaced-nav-items-component.png) ## See Also - [How to Replace PermissionManagementComponent](./Permission-Management-Component-Replacement.md) ## What's Next? - [Custom Setting Page](./Custom-Setting-Page.md)