diff --git a/docs/en/UI/Angular/Component-Replacement.md b/docs/en/UI/Angular/Component-Replacement.md
index fb85aa476e..b11acbc6b5 100644
--- a/docs/en/UI/Angular/Component-Replacement.md
+++ b/docs/en/UI/Angular/Component-Replacement.md
@@ -1,10 +1,10 @@
-## Component Replacement
+# 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
+## 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`.
@@ -15,16 +15,20 @@ import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddRepl
import { eIdentityComponents } from '@abp/ng.identity'; // imported eIdentityComponents enum
import { Store } from '@ngxs/store'; // imported Store
//...
-export class AppComponent {
+
+@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,
}),
);
+
//...
}
}
@@ -33,13 +37,13 @@ export class AppComponent {

-### How to Replace a Layout
+## How to Replace a Layout
-Each ABP theme module has 3 layouts named `ApplicationLayoutComponent`, `AccountLayoutComponent`, `EmptyLayoutComponent`. These layouts can be replaced with the same way.
+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 below example describes how to replace the `ApplicationLayoutComponent`:
+The example below describes how to replace the `ApplicationLayoutComponent`:
Run the following command to generate a layout in `angular` folder:
@@ -55,7 +59,7 @@ Add the following code in your layout template (`my-layout.component.html`) wher
```
-Open the `app.component.ts` and add the below content:
+Open `app.component.ts` in `src/app` folder and modify it as shown below:
```js
import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent
@@ -63,11 +67,13 @@ import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeB
import { MyApplicationLayoutComponent } from './shared/my-application-layout/my-application-layout.component'; // imported MyApplicationLayoutComponent
import { Store } from '@ngxs/store'; // imported Store
//...
-export class AppComponent {
+
+@Component(/* component metadata */)
+export class AppComponent implements OnInit {
constructor(..., private store: Store) {} // injected Store
ngOnInit() {
- // added below content
+ // added dispatch
this.store.dispatch(
new AddReplaceableComponent({
component: MyApplicationLayoutComponent,
@@ -80,6 +86,463 @@ export class AppComponent {
}
```
+### Layout Components
+
+
+
+#### How to Replace LogoComponent
+
+
+
+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: `
+
+
+
+
+ `,
+})
+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:
+
+
+
+#### How to Replace RoutesComponent
+
+
+
+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:
+
+
+
+#### How to Replace NavItemsComponent
+
+
+
+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:
+
+
+
## What's Next?
- [Custom Setting Page](./Custom-Setting-Page.md)
diff --git a/docs/en/UI/Angular/images/layout-components.png b/docs/en/UI/Angular/images/layout-components.png
new file mode 100644
index 0000000000..3193b47bd1
Binary files /dev/null and b/docs/en/UI/Angular/images/layout-components.png differ
diff --git a/docs/en/UI/Angular/images/logo-component.png b/docs/en/UI/Angular/images/logo-component.png
new file mode 100644
index 0000000000..5c11fbf617
Binary files /dev/null and b/docs/en/UI/Angular/images/logo-component.png differ
diff --git a/docs/en/UI/Angular/images/nav-items-component.png b/docs/en/UI/Angular/images/nav-items-component.png
new file mode 100644
index 0000000000..d3e69916b6
Binary files /dev/null and b/docs/en/UI/Angular/images/nav-items-component.png differ
diff --git a/docs/en/UI/Angular/images/replaced-logo-component.png b/docs/en/UI/Angular/images/replaced-logo-component.png
new file mode 100644
index 0000000000..4661b390a8
Binary files /dev/null and b/docs/en/UI/Angular/images/replaced-logo-component.png differ
diff --git a/docs/en/UI/Angular/images/replaced-nav-items-component.png b/docs/en/UI/Angular/images/replaced-nav-items-component.png
new file mode 100644
index 0000000000..e4cc0339ae
Binary files /dev/null and b/docs/en/UI/Angular/images/replaced-nav-items-component.png differ
diff --git a/docs/en/UI/Angular/images/replaced-routes-component.png b/docs/en/UI/Angular/images/replaced-routes-component.png
new file mode 100644
index 0000000000..3a6336afe0
Binary files /dev/null and b/docs/en/UI/Angular/images/replaced-routes-component.png differ
diff --git a/docs/en/UI/Angular/images/routes-component.png b/docs/en/UI/Angular/images/routes-component.png
new file mode 100644
index 0000000000..b708e86d36
Binary files /dev/null and b/docs/en/UI/Angular/images/routes-component.png differ