Browse Source

Merge pull request #23285 from abpframework/sumeyye/standalone-migration-documentation-updates

Angular - Documentation updates for standalone migration
pull/23583/head
sumeyye 1 year ago
committed by GitHub
parent
commit
0946c5797b
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 10
      docs/en/framework/architecture/multi-tenancy/index.md
  2. 71
      docs/en/framework/ui/angular/account-module.md
  3. 30
      docs/en/framework/ui/angular/authorization.md
  4. 5
      docs/en/framework/ui/angular/basic-theme.md
  5. 51
      docs/en/framework/ui/angular/caps-lock-directive.md
  6. 98
      docs/en/framework/ui/angular/card-component.md
  7. 36
      docs/en/framework/ui/angular/chart-component.md
  8. 141
      docs/en/framework/ui/angular/component-replacement.md
  9. 50
      docs/en/framework/ui/angular/config-state-service.md
  10. 25
      docs/en/framework/ui/angular/confirmation-service.md
  11. 16
      docs/en/framework/ui/angular/data-table-column-extensions.md
  12. 18
      docs/en/framework/ui/angular/dynamic-form-extensions.md
  13. 49
      docs/en/framework/ui/angular/ellipsis-directive.md
  14. 93
      docs/en/framework/ui/angular/entity-action-extensions.md
  15. 33
      docs/en/framework/ui/angular/entity-filters.md
  16. 26
      docs/en/framework/ui/angular/environment.md
  17. 4
      docs/en/framework/ui/angular/extensions-overall.md
  18. 41
      docs/en/framework/ui/angular/feature-libraries.md
  19. 64
      docs/en/framework/ui/angular/form-validation.md
  20. 59
      docs/en/framework/ui/angular/http-error-handling.md
  21. BIN
      docs/en/framework/ui/angular/images/quick-start---root-folder-structure.png
  22. BIN
      docs/en/framework/ui/angular/images/quick-start---source-folder-structure.png
  23. 1
      docs/en/framework/ui/angular/list-service.md
  24. 17
      docs/en/framework/ui/angular/loading-directive.md
  25. 74
      docs/en/framework/ui/angular/localization.md
  26. 25
      docs/en/framework/ui/angular/lookup-components.md
  27. 57
      docs/en/framework/ui/angular/manage-profile-page-tabs.md
  28. 69
      docs/en/framework/ui/angular/modal.md
  29. 90
      docs/en/framework/ui/angular/modifying-the-menu.md
  30. 13
      docs/en/framework/ui/angular/multi-tenancy.md
  31. 3
      docs/en/framework/ui/angular/oauth-module.md
  32. 84
      docs/en/framework/ui/angular/page-component.md
  33. 32
      docs/en/framework/ui/angular/page-toolbar-extensions.md
  34. 2
      docs/en/framework/ui/angular/password-complexity-indicator-component.md
  35. 9
      docs/en/framework/ui/angular/permission-management.md
  36. 2
      docs/en/framework/ui/angular/pwa-configuration.md
  37. 21
      docs/en/framework/ui/angular/quick-start.md
  38. 36
      docs/en/framework/ui/angular/show-password-directive.md
  39. 11
      docs/en/framework/ui/angular/sorting-navigation-elements.md
  40. 12
      docs/en/framework/ui/angular/toaster-service.md
  41. BIN
      docs/en/images/angular-folder-structure.png
  42. 42
      docs/en/modules/account-pro.md
  43. 38
      docs/en/modules/audit-logging-pro.md
  44. 35
      docs/en/modules/chat.md
  45. 43
      docs/en/modules/gdpr.md
  46. 38
      docs/en/modules/identity-pro.md
  47. 36
      docs/en/modules/identity-server-pro.md
  48. 40
      docs/en/modules/language-management.md
  49. 34
      docs/en/modules/payment.md
  50. 38
      docs/en/modules/saas.md
  51. 38
      docs/en/modules/text-template-management.md
  52. 38
      docs/en/solution-templates/application-module/index.md
  53. BIN
      docs/en/solution-templates/layered-web-application/images/angular-folder-structure.png
  54. BIN
      docs/en/solution-templates/layered-web-application/images/angular-template-structure-diagram.png
  55. 26
      docs/en/solution-templates/layered-web-application/web-applications.md
  56. 9
      docs/en/solution-templates/microservice/localization-system.md
  57. 34
      docs/en/suite/solution-structure.md
  58. 103
      docs/en/tutorials/microservice/part-05.md
  59. 39
      docs/en/ui-themes/lepton-x-lite/angular.md
  60. 57
      docs/en/ui-themes/lepton-x/angular.md
  61. 16
      docs/en/ui-themes/lepton-x/angular/how-to-add-a-new-variation-to-lepton-x-for-angular.md
  62. 29
      docs/en/ui-themes/lepton-x/angular/how-to-change-default-theme-option.md
  63. 23
      docs/en/ui-themes/lepton-x/how-to-use-lepton-x-components-with-angular-custom-layout.md
  64. 81
      docs/en/ui-themes/lepton/customizing-lepton-theme.md
  65. 2
      npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts

10
docs/en/framework/architecture/multi-tenancy/index.md

@ -231,18 +231,20 @@ services.Configure<AbpAspNetCoreMultiTenancyOptions>(options =>
If you change the `TenantKey`, make sure to pass it to `provideAbpCore` via `withOptions` method in the Angular client as follows: If you change the `TenantKey`, make sure to pass it to `provideAbpCore` via `withOptions` method in the Angular client as follows:
```js ```js
@NgModule({ // app.config.ts
// ...
export const appConfig: ApplicationConfig = {
providers: [ providers: [
// ...
provideAbpCore( provideAbpCore(
withOptions({ withOptions({
// ... // ...
tenantKey: "MyTenantKey", tenantKey: "MyTenantKey",
}) })
), ),
// ...
], ],
// ... };
})
export class AppModule {}
``` ```
If you need to access it, you can inject it as follows: If you need to access it, you can inject it as follows:

71
docs/en/framework/ui/angular/account-module.md

@ -17,36 +17,35 @@ npm install @abp/ng.account
> Make sure v4.3 or higher version is installed. > Make sure v4.3 or higher version is installed.
Open the `app.module.ts` and add `provideAccountConfig()` to the providers array as shown below: Open the `app.config.ts` and add `provideAccountConfig()` to the providers array as shown below:
```js ```js
// app.module.ts // app.config.ts
import { provideAccountConfig } from "@abp/ng.account/config"; import { provideAccountConfig } from "@abp/ng.account/config";
//... // ...
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
//... // ...
provideAccountConfig(), provideAccountConfig(),
// ...
], ],
//... };
})
export class AppModule {}
``` ```
Open the `app-routing.module.ts` and add the `account` route to `routes` array as follows: Open the `app.routes.ts` and add the `account` route to `APP_ROUTES` array as follows:
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [ export const APP_ROUTES: Routes = [
//... //...
{ {
path: 'account', path: 'account',
loadChildren: () => import('@abp/ng.account').then(m => m.AccountModule.forLazy()), loadChildren: () => import('@abp/ng.account').then(c => c.createRoutes()),
}, },
//... //...
export class AppRoutingModule {} ];
``` ```
## Account Public Module Implementation for Commercial Templates ## Account Public Module Implementation for Commercial Templates
@ -59,42 +58,42 @@ npm install @volo/abp.ng.account
> Make sure v4.3 or higher version is installed. > Make sure v4.3 or higher version is installed.
Open the `app.module.ts` and add `AccountPublicConfigModule.forRoot()` to the imports array as shown below: Open the `app.config.ts` and add `provideAccountPublicConfig()` to the providers array as shown below:
> Ensure that the `Account Layout Module` has been added if you are using the Lepton X theme. If you miss the step, you will get an error message that says `Account layout not found. Please check your configuration. If you are using LeptonX, please make sure you have added "AccountLayoutModule.forRoot()" to your app.module configuration.` when you try to access the account pages. Otherwise, you can skip adding the `AccountLayoutModule` step. > Ensure that the `Account Layout Provider` has been added if you are using the Lepton X theme. If you miss the step, you will get an error message that says `Account layout not found. Please check your configuration. If you are using LeptonX, please make sure you have added "provideAccountLayout()" to your app configuration.` Otherwise, you can skip adding the `provideAccountLayout()` step.
```js ```js
// app.module.ts // app.config.ts
import { AccountPublicConfigModule } from "@volo/abp.ng.account/public/config"; import { provideAccountPublicConfig } from "@volo/abp.ng.account/public/config";
// if you are using or want to use Lepton X, you should add AccountLayoutModule // if you are using or want to use Lepton X, you should add provideAccountLayout
// import { AccountLayoutModule } from '@volosoft/abp.ng.theme.lepton-x/account' // import { provideAccountLayout } from '@volosoft/abp.ng.theme.lepton-x/account'
//... //...
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
//... // ...
AccountPublicConfigModule.forRoot(), provideAccountPublicConfig(),
// AccountLayoutModule.forRoot() // Only for Lepton X provideAccountLayout() // Only for Lepton X
// ...
], ],
//... };
})
export class AppModule {}
``` ```
Open the `app-routing.module.ts` and add the `account` route to `routes` array as follows: Open the `app.routes.ts` and add the `account` route to `APP_ROUTES` array as follows:
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [
export const APP_ROUTES: Routes = [
//... //...
{ {
path: 'account', path: 'account',
loadChildren: () => import('@volo/abp.ng.account/public').then(m => m.AccountPublicModule.forLazy()), loadChildren: () => import('@volo/abp.ng.account/public').then(c => c.createRoutes()),
}, },
//... //...
export class AppRoutingModule {} ];
``` ```
## My Account Page ## My Account Page
@ -108,15 +107,15 @@ When the user changes their own data on the personal settings tab in My Account,
If you want to disable these warning, You should set `isPersonalSettingsChangedConfirmationActive` false If you want to disable these warning, You should set `isPersonalSettingsChangedConfirmationActive` false
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [ export const APP_ROUTES: Routes = [
//... //...
{ {
path: 'account', path: 'account',
loadChildren: () => import('@volo/abp.ng.account/public').then(m => m.AccountPublicModule.forLazy({ isPersonalSettingsChangedConfirmationActive:false })), loadChildren: () => import('@volo/abp.ng.account/public').then(c => c.create({ isPersonalSettingsChangedConfirmationActive:false })),
}, },
//... //...
export class AppRoutingModule {} ];
``` ```
## Security Logs Page [COMMERCIAL] ## Security Logs Page [COMMERCIAL]

30
docs/en/framework/ui/angular/authorization.md

@ -61,15 +61,18 @@ The `AuthErrorFilterService` is an abstract service that needs to be replaced wi
### Usage ### Usage
#### 1.Create an auth-filter.provider #### 1.Create an auth filter provider
```js ```js
import { APP_INITIALIZER, inject } from '@angular/core'; //auth-filter.provider.ts
import { inject, provideAppInitializer } from '@angular/core';
import { AuthErrorFilter, AuthErrorEvent, AuthErrorFilterService } from '@abp/ng.core'; import { AuthErrorFilter, AuthErrorEvent, AuthErrorFilterService } from '@abp/ng.core';
import { eCustomersAuthFilterNames } from '../enums'; import { eCustomersAuthFilterNames } from '../enums';
export const CUSTOMERS_AUTH_FILTER_PROVIDER = [ export const CUSTOMERS_AUTH_FILTER_PROVIDER = [
{ provide: APP_INITIALIZER, useFactory: configureAuthFilter, multi: true }, provideAppInitializer(() => {
configureAuthFilter()
}),
]; ];
type Reason = object & { error: { grant_type: string | undefined } }; type Reason = object & { error: { grant_type: string | undefined } };
@ -100,20 +103,17 @@ function configureAuthFilter() {
- `executable:` a status for the filter object. If it's false then it won't work, yet it'll stay in the list - `executable:` a status for the filter object. If it's false then it won't work, yet it'll stay in the list
- `execute:` a function that stores the skip logic - `execute:` a function that stores the skip logic
#### 2.Add to the FeatureConfigModule #### 2.Add to the customer configuration provider
```js ```js
import { ModuleWithProviders, NgModule } from "@angular/core"; // customer-config.provider.ts
import { CUSTOMERS_AUTH_FILTER_PROVIDER } from "./providers/auth-filter.provider"; import { EnvironmentProviders, makeEnvironmentProviders } from "@angular/core";
import { CUSTOMERS_AUTH_FILTER_PROVIDER } from "./auth-filter.provider";
@NgModule()
export class CustomersConfigModule { export function provideCustomerConfig(): EnvironmentProviders {
static forRoot(): ModuleWithProviders<CustomersConfigModule> { return makeEnvironmentProviders([
return { CUSTOMERS_AUTH_FILTER_PROVIDER
ngModule: CustomersConfigModule, ])
providers: [CUSTOMERS_AUTH_FILTER_PROVIDER],
};
}
} }
``` ```

5
docs/en/framework/ui/angular/basic-theme.md

@ -11,10 +11,9 @@ The Basic Theme is a theme implementation for the Angular UI. It is a minimalist
If you need to manually this theme, follow the steps below: If you need to manually this theme, follow the steps below:
* Install the [@abp/ng.theme.basic](https://www.npmjs.com/package/@abp/ng.theme.basic) NPM package to your Angular project. * Install the [@abp/ng.theme.basic](https://www.npmjs.com/package/@abp/ng.theme.basic) NPM package to your Angular project.
* Open the `src/app/app.module.ts` file, import `ThemeBasicModule`,`provideThemeBasicConfig` (it can be imported from `@abp/ng.theme.basic` package), and add `ThemeBasicModule` to the `imports` array and provide `provideThemeBasicConfig()` to the providers array. * Open the `src/app/app.config.ts` file, import `provideThemeBasicConfig` (it can be imported from `@abp/ng.theme.basic` package), and provide `provideThemeBasicConfig()` to the providers array.
* Open the `src/app/shared/shared.module` file, import `ThemeBasicModule` (it can be imported from `@abp/ng.theme.basic` package), and add `ThemeBasicModule` to the `imports` and `exports` array.
The `ThemeBasicModule` is registered own layouts (`ApplicationLayoutComponent`, `AccountLayoutComponent`, `EmptyLayoutComponent`) to a service which is exposed by `@abp/ng.core` package on application initialization. The `BASIC_THEME_STYLES_PROVIDERS` has registered three layouts being `ApplicationLayoutComponent`, `AccountLayoutComponent`, and `EmptyLayoutComponent`. These are provided inside `provideThemeBasicConfig()` function that is exposed by `@abp/ng.theme.basic` package on application initialization.
## Application Layout ## Application Layout

51
docs/en/framework/ui/angular/caps-lock-directive.md

@ -5,66 +5,27 @@ In password inputs, You may want to show if Caps Lock is on. To make this even e
## Getting Started ## Getting Started
`TrackCapsLockDirective` is standalone. In order to use the `TrackCapsLockDirective` in an HTML template, import it to related module or your standalone component: `TrackCapsLockDirective` is standalone. In order to use the `TrackCapsLockDirective` in an HTML template, import it to related component. The selector of the directive is **`abpCapsLock`**. By adding the `abpCapsLock` event to an element, you can track the status of Caps Lock. You can use this to warn user.
**Importing to NgModule**
```ts
import { TrackCapsLockDirective } from '@abp/ng.core';
@NgModule({
//...
declarations: [
...,
TestComponent
],
imports: [
...,
TrackCapsLockDirective
],
})
export class MyFeatureModule {}
```
## Usage
The `TrackCapsLockDirective` is very easy to use. The directive's selector is **`abpCapsLock`**. By adding the `abpCapsLock` event to an element, you can track the status of Caps Lock. You can use this to warn user.
See an example usage: See an example usage:
**NgModule Component usage**
```ts
@Component({
selector: 'test-component',
template: `
<div class="d-flex flex-column">
<label>Password</label>
<input (abpCapsLock)="capsLock = $event"/>
<i *ngIf="capsLock">icon</i>
</div>
`
})
export class TestComponent{
capsLock = false;
}
```
**Standalone Component usage**
```ts ```ts
import { TrackCapsLockDirective } from '@abp/ng.core' import { TrackCapsLockDirective } from '@abp/ng.core'
@Component({ @Component({
selector: 'standalone-component', selector: 'sample-component',
standalone: true,
template: ` template: `
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<label>Password</label> <label>Password</label>
<input (abpCapsLock)="capsLock = $event"/> <input (abpCapsLock)="capsLock = $event"/>
<i *ngIf="capsLock">icon</i> @if (capslock) {
<i>icon</i>
}
</div> </div>
`, `,
imports: [TrackCapsLockDirective] imports: [TrackCapsLockDirective]
}) })
export class StandaloneComponent{ export class SampleComponent{
capsLock = false; capsLock = false;
} }
``` ```

98
docs/en/framework/ui/angular/card-component.md

@ -23,27 +23,7 @@ In addition to these components, the Card component provides directives like `Ca
# Usage # Usage
ABP Card Component is a part of the `ThemeSharedModule` module. If you've imported that module into your module, you don't need to import it again. If not, first import it as shown below: ABP Card Component is a part of the `theme-shared` package. Once you import the necessary components, you can use them. See the examples below:
```ts
// my-feature.module.ts
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { CardDemoComponent } from './card-demo.component';
@NgModule({
imports: [
ThemeSharedModule ,
// ...
],
declarations: [CardDemoComponent],
// ...
})
export class MyFeatureModule {}
```
Then, the `abp-card` component can be used. See the examples below:
## CardBody ## CardBody
@ -51,16 +31,18 @@ Then, the `abp-card` component can be used. See the examples below:
// card-demo.component.ts // card-demo.component.ts
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { CardComponent, CardBodyComponent } from '@abp/ng.theme.shared';
@Component({ @Component({
selector: 'app-card-demo', selector: 'app-card-demo',
imports: [CardComponent, CardBodyComponent],
template: ` template: `
<abp-card [cardStyle]="{width: '18rem'}"> <abp-card [cardStyle]="{width: '18rem'}">
<abp-card-body>This is some text within a card body</abp-card-body> <abp-card-body>This is some text within a card body</abp-card-body>
</abp-card> </abp-card>
`, `,
}) })
export class CardDemoComponent { } export class CardDemoComponent {}
``` ```
See the card body result below: See the card body result below:
@ -72,22 +54,36 @@ See the card body result below:
//card-demo.component.ts //card-demo.component.ts
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import {
CardComponent,
CardBodyComponent,
CardTitleDirective,
CardSubtitleDirective
} from '@abp/ng.theme.shared';
@Component({ @Component({
selector: 'app-card-demo', selector: 'app-card-demo',
imports: [
CardComponent,
CardBodyComponent,
CardTitleDirective,
CardSubtitleDirective
],
template: ` template: `
<abp-card [cardStyle]="{width: '18rem'}"> <abp-card [cardStyle]="{width: '18rem'}">
<abp-card-body> <abp-card-body>
<h5 abpCardTitle>Card Title</h5> <h5 abpCardTitle>Card Title</h5>
<h6 abpCardSubtitle class="mb-2 text-muted">Card subtitle</h6> <h6 abpCardSubtitle class="mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p> <p class="card-text">
<a href="#" class="card-link" >Card link</a> Some quick example text to build on the card title and make up the bulk of the card's content.
<a href="#" class="card-link" >Another link</a> </p>
<a href="#" class="card-link">Card link</a>
<a href="#" class="card-link">Another link</a>
</abp-card-body> </abp-card-body>
</abp-card> </abp-card>
`, `,
}) })
export class CardDemoComponent { } export class CardDemoComponent {}
``` ```
See the card title, text and link result below: See the card title, text and link result below:
@ -99,19 +95,23 @@ See the card title, text and link result below:
//card-demo.component.ts //card-demo.component.ts
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { CardComponent, CardBodyComponent, CardImgTopDirective } from '@abp/ng.theme.shared';
@Component({ @Component({
selector: 'app-card-demo', selector: 'app-card-demo',
imports: [CardComponent, CardBodyComponent, CardImgTopDirective],
template: ` template: `
<abp-card [cardStyle]="{width:'18rem'}"> <abp-card [cardStyle]="{width:'18rem'}">
<img abpCardImgTop src="..." alt="..."> <img abpCardImgTop src="..." alt="...">
<abp-card-body> <abp-card-body>
<p class="card-text" >Some quick example text to build on the card title and make up the bulk of the card's content.</p> <p class="card-text">
Some quick example text to build on the card title and make up the bulk of the card's content.
</p>
</abp-card-body> </abp-card-body>
</abp-card> </abp-card>
`, `,
}) })
export class CardDemoComponent { } export class CardDemoComponent {}
``` ```
See the card image result below: See the card image result below:
@ -123,9 +123,11 @@ See the card image result below:
//card-demo.component.ts //card-demo.component.ts
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { CardComponent } from '@abp/ng.theme.shared';
@Component({ @Component({
selector: 'app-card-demo', selector: 'app-card-demo',
imports: [CardComponent],
template: ` template: `
<abp-card [cardStyle]="{width:'18rem'}"> <abp-card [cardStyle]="{width:'18rem'}">
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">
@ -136,7 +138,7 @@ import { Component } from '@angular/core';
</abp-card> </abp-card>
`, `,
}) })
export class CardDemoComponent { } export class CardDemoComponent {}
``` ```
See the group list result below: See the group list result below:
@ -148,15 +150,29 @@ See the group list result below:
//card-demo.component.ts //card-demo.component.ts
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import {
CardComponent,
CardBodyComponent,
CardImgTopDirective,
CardTitleDirective
} from '@abp/ng.theme.shared';
@Component({ @Component({
selector: 'app-card-demo', selector: 'app-card-demo',
imports: [
CardComponent,
CardBodyComponent,
CardImgTopDirective,
CardTitleDirective
],
template: ` template: `
<abp-card [cardStyle]="{width:'18rem'}"> <abp-card [cardStyle]="{width:'18rem'}">
<img abpCardImgTop src="../../assets/thinh-nguyen-aRrS37GKlVA-unsplash.jpg" alt="..."> <img abpCardImgTop src="../../assets/thinh-nguyen-aRrS37GKlVA-unsplash.jpg" alt="...">
<abp-card-body> <abp-card-body>
<h5 abpCardTitle>Card title</h5> <h5 abpCardTitle>Card title</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p> <p class="card-text">
Some quick example text to build on the card title and make up the bulk of the card's content.
</p>
</abp-card-body> </abp-card-body>
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">
<li class="list-group-item">An item</li> <li class="list-group-item">An item</li>
@ -170,7 +186,7 @@ import { Component } from '@angular/core';
</abp-card> </abp-card>
`, `,
}) })
export class CardDemoComponent { } export class CardDemoComponent {}
``` ```
See kitchen sink result below: See kitchen sink result below:
@ -182,15 +198,31 @@ See kitchen sink result below:
//card-demo.component.ts //card-demo.component.ts
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import {
CardComponent,
CardHeaderComponent,
CardBodyComponent,
CardTitleDirective,
CardFooterComponent
} from '@abp/ng.theme.shared';
@Component({ @Component({
selector: 'app-card-demo', selector: 'app-card-demo',
imports: [
CardComponent,
CardHeaderComponent,
CardBodyComponent,
CardTitleDirective,
CardFooterComponent
],
template: ` template: `
<abp-card class="text-center"> <abp-card class="text-center">
<abp-card-header>Featured</abp-card-header> <abp-card-header>Featured</abp-card-header>
<abp-card-body> <abp-card-body>
<h5 abpCardTitle>Special title treatment</h5> <h5 abpCardTitle>Special title treatment</h5>
<p class="card-text">With supporting text below as a natural lead-in to additional content.</p> <p class="card-text">
With supporting text below as a natural lead-in to additional content.
</p>
<a class="card-link" href="#" class="btn btn-primary">Go somewhere</a> <a class="card-link" href="#" class="btn btn-primary">Go somewhere</a>
</abp-card-body> </abp-card-body>
<abp-card-footer class="text-muted"> <abp-card-footer class="text-muted">
@ -199,7 +231,7 @@ import { Component } from '@angular/core';
</abp-card> </abp-card>
`, `,
}) })
export class CardDemoComponent { } export class CardDemoComponent {}
``` ```
See the header and footer result below: See the header and footer result below:

36
docs/en/framework/ui/angular/chart-component.md

@ -6,34 +6,16 @@ ABP Chart component exposed by `@abp/ng.components/chart.js` is based on [`chart
## How to Use ## How to Use
First of all, need to import the `ChartModule` to your feature module as follows: First of all, need to import the `ChartComponent` to your component. Then, `abp-chart` component can be used. See an example:
```ts
// your-feature.module.ts
import { ChartModule } from "@abp/ng.components/chart.js";
import { ChartDemoComponent } from "./chart-demo.component";
@NgModule({
imports: [
ChartModule,
// ...
],
declarations: [ChartDemoComponent],
// ...
})
export class YourFeatureModule {}
```
Then, `abp-chart` component can be used. See an example:
```ts ```ts
// chart-demo.component.ts // chart-demo.component.ts
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { ChartComponent } from "@abp/ng.components/chart.js";
@Component({ @Component({
selector: "app-chart-demo", selector: "app-chart-demo",
imports: [ChartComponent],
template: ` <abp-chart type="pie" [data]="data"></abp-chart> `, template: ` <abp-chart type="pie" [data]="data"></abp-chart> `,
}) })
export class ChartDemoComponent { export class ChartDemoComponent {
@ -62,9 +44,11 @@ See the result:
```ts ```ts
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { ChartComponent } from "@abp/ng.components/chart.js";
@Component({ @Component({
selector: "app-chart-demo", selector: "app-chart-demo",
imports: [ChartComponent],
template: ` template: `
<abp-chart <abp-chart
type="doughnut" type="doughnut"
@ -73,7 +57,7 @@ import { Component } from "@angular/core";
width="400px" width="400px"
height="400px" height="400px"
[plugins]="myPlugin" [plugins]="myPlugin"
></abp-chart> />
`, `,
}) })
export class ChartDemoComponent { export class ChartDemoComponent {
@ -119,16 +103,18 @@ Result:
```ts ```ts
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { ChartComponent } from "@abp/ng.components/chart.js";
@Component({ @Component({
selector: "app-chart-demo", selector: "app-chart-demo",
imports: [ChartComponent]
template: ` template: `
<abp-chart <abp-chart
type="bar" type="bar"
[data]="data" [data]="data"
width="400px" width="400px"
height="400px" height="400px"
></abp-chart> />
`, `,
}) })
export class ChartDemoComponent { export class ChartDemoComponent {
@ -158,16 +144,18 @@ Result:
```ts ```ts
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { ChartComponent } from "@abp/ng.components/chart.js";
@Component({ @Component({
selector: "app-chart-demo", selector: "app-chart-demo",
imports: [ChartComponent]
template: ` template: `
<abp-chart <abp-chart
type="radar" type="radar"
[data]="data" [data]="data"
width="400px" width="400px"
height="400px" height="400px"
></abp-chart> />
<button class="btn btn-primary-outline mt-4" (click)="addDataset()"> <button class="btn btn-primary-outline mt-4" (click)="addDataset()">
Add dataset Add dataset

141
docs/en/framework/ui/angular/component-replacement.md

@ -6,7 +6,7 @@ The reason that you **can replace** but **cannot customize** default ABP compone
## 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`. Create a new component that you want to use instead of an ABP component.
Then, open the `app.component.ts` and execute the `add` method of `ReplaceableComponentsService` 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:
@ -32,7 +32,7 @@ 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 the same way. Each ABP theme package has 3 layouts named `ApplicationLayoutComponent`, `AccountLayoutComponent`, `EmptyLayoutComponent`. These layouts can be replaced the same way.
> A layout component template should contain `<router-outlet></router-outlet>` element. > A layout component template should contain `<router-outlet></router-outlet>` element.
@ -70,7 +70,7 @@ export class AppComponent {
} }
``` ```
> 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. > If you would 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
@ -96,8 +96,6 @@ This command will create a new component named `new-layout`. Now, open the new-l
This 'router-outlet' will act as a placeholder that Angular dynamically fills based on the current router state. This 'router-outlet' will act as a placeholder that Angular dynamically fills based on the current router state.
note: (don't forget: you should add the app in the app.module.ts file)
#### Step 2: Define a Variable for the Layout Component #### Step 2: Define a Variable for the Layout Component
Although this step is optional, it can be useful if you're going to use the layout component's value multiple times. You can define a variable for the layout component like this: Although this step is optional, it can be useful if you're going to use the layout component's value multiple times. You can define a variable for the layout component like this:
@ -116,33 +114,29 @@ You can use this variable when you need to refer to the layout component.
Next, you need to add the new layout component to the `ReplaceableComponentsService`. This service allows you to replace a component with another one dynamically. Next, you need to add the new layout component to the `ReplaceableComponentsService`. This service allows you to replace a component with another one dynamically.
You can do this by defining a provider for `APP_INITIALIZER` that uses a factory function. In this function, you inject the `ReplaceableComponentsService` and use its `add` method to add the new layout component. You can do this by defining a provider for `provideAppInitializer` that uses a factory function. In this function, you inject the `ReplaceableComponentsService` and use its `add` method to add the new layout component.
Here's how you can do it: Here's how you can do it:
```javascript ```javascript
export const CUSTOM_LAYOUT_PROVIDERS = [ export const CUSTOM_LAYOUT_PROVIDERS = [
{ provideAppInitializer(()=>{
provide: APP_INITIALIZER, configureLayoutFn();
useFactory: configureLayoutFn, }),
deps: [ReplaceableComponentsService],
multi: true,
},
]; ];
function configureLayoutFn() { function configureLayoutFn() {
const service = inject(ReplaceableComponentsService); const service = inject(ReplaceableComponentsService);
return () => { service.add({
service.add({ key: eCustomLayout.component,
key: eCustomLayout.component, component: CustomLayoutComponent,
component: CustomLayoutComponent, });
});
};
} }
``` ```
In this code, `configureLayoutFn` is a factory function that adds the new layout component to the `ReplaceableComponentsService`. The `APP_INITIALIZER` provider runs this function when the application starts. In this code, `configureLayoutFn` is a factory function that adds the new layout component to the `ReplaceableComponentsService`. The `provideAppInitializer` provider runs this function when the application starts.
note: (don't forget: you should add the CUSTOM_LAYOUT_PROVIDERS in the app.module.ts file) note: (don't forget: you should add the CUSTOM_LAYOUT_PROVIDERS in the app.config.ts file)
#### Step 4: Define the Application's Dynamic Layouts #### Step 4: Define the Application's Dynamic Layouts
@ -154,14 +148,14 @@ You can add the new layout to the existing layouts like this:
export const myDynamicLayouts = new Map<string, string>([...DEFAULT_DYNAMIC_LAYOUTS, [eCustomLayout.key, eCustomLayout.component]]); export const myDynamicLayouts = new Map<string, string>([...DEFAULT_DYNAMIC_LAYOUTS, [eCustomLayout.key, eCustomLayout.component]]);
``` ```
#### Step 5: Pass the Dynamic Layouts to the CoreModule #### Step 5: Pass the Dynamic Layouts to the Core Provider
The final step is to pass the dynamic layouts to the `provideAbpCore` using the `withOptions` method. This method allows you to configure the module with a static method. The final step is to pass the dynamic layouts to the `provideAbpCore` using the `withOptions` method. This method allows you to configure the provider with a static method.
Here's how you can do it: Here's how you can do it:
```ts ```ts
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
// ... // ...
provideAbpCore( provideAbpCore(
@ -172,8 +166,7 @@ Here's how you can do it:
}), }),
), ),
], ],
}) };
export class AppModule {}
``` ```
In this code, `myDynamicLayouts` is the map of dynamic layouts you defined earlier. We pass this map to the `provideAbpCore` using the `withOptions` method. In this code, `myDynamicLayouts` is the map of dynamic layouts you defined earlier. We pass this map to the `provideAbpCore` using the `withOptions` method.
@ -186,32 +179,33 @@ Here's how you can do it:
// route.provider.ts // route.provider.ts
import { eCustomLayout } from './custom-layout/custom-layout.provider'; import { eCustomLayout } from './custom-layout/custom-layout.provider';
import { RoutesService, eLayoutType } from '@abp/ng.core'; import { RoutesService, eLayoutType } from '@abp/ng.core';
import { APP_INITIALIZER } from '@angular/core'; import { provideAppInitializer } from '@angular/core';
export const APP_ROUTE_PROVIDER = [ export const APP_ROUTE_PROVIDER = [
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true }, provideAppInitializer(() => {
configureRoutes();
}),
]; ];
function configureRoutes(routes: RoutesService) { function configureRoutes() {
return () => { const routes = inject(RoutesService);
routes.add([ routes.add([
{ {
path: '/', path: '/',
name: '::Menu:Home', name: '::Menu:Home',
iconClass: 'fas fa-home', iconClass: 'fas fa-home',
order: 1, order: 1,
layout: eLayoutType.application, layout: eLayoutType.application,
}, },
{ {
path: '/dashboard', path: '/dashboard',
name: '::Menu:Dashboard', name: '::Menu:Dashboard',
iconClass: 'fas fa-chart-line', iconClass: 'fas fa-chart-line',
order: 2, order: 2,
layout: eCustomLayout.key as eLayoutType, layout: eCustomLayout.key as eLayoutType,
requiredPolicy: 'MyProjectName.Dashboard.Host || MyProjectName.Dashboard.Tenant', requiredPolicy: 'MyProjectName.Dashboard.Host || MyProjectName.Dashboard.Tenant',
}, },
]); ]);
};
} }
``` ```
@ -288,10 +282,23 @@ Open the generated `routes.component.ts` in `src/app/routes` folder and replace
```js ```js
import { Component, HostBinding } from "@angular/core"; import { Component, HostBinding } from "@angular/core";
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { LocalizationPipe, PermissionDirective } from "@abp/ng.core";
import { EllipsisDirective } from '@abp/ng.theme.shared';
@Component({ @Component({
selector: "app-routes", selector: "app-routes",
templateUrl: "routes.component.html", templateUrl: "routes.component.html",
imports: [
CommonModule,
RouterModule,
NgbDropdownModule,
PermissionDirective,
EllipsisDirective,
LocalizationPipe,
]
}) })
export class RoutesComponent { export class RoutesComponent {
@HostBinding("class.mx-auto") @HostBinding("class.mx-auto")
@ -303,21 +310,6 @@ export class RoutesComponent {
} }
``` ```
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: Open the generated `routes.component.html` in `src/app/routes` folder and replace its content with the following:
```html ```html
@ -482,8 +474,12 @@ import {
LanguageInfo, LanguageInfo,
NAVIGATE_TO_MANAGE_PROFILE, NAVIGATE_TO_MANAGE_PROFILE,
SessionStateService, SessionStateService,
LocalizationPipe
} from '@abp/ng.core'; } from '@abp/ng.core';
import { Component, Inject } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import snq from 'snq'; import snq from 'snq';
@ -491,6 +487,12 @@ import snq from 'snq';
@Component({ @Component({
selector: 'app-nav-items', selector: 'app-nav-items',
templateUrl: 'nav-items.component.html', templateUrl: 'nav-items.component.html',
imports: [
CommonModule,
FormsModule,
NgbDropdownModule,
LocalizationPipe
]
}) })
export class NavItemsComponent { export class NavItemsComponent {
currentUser$: Observable<CurrentUserDto> = this.configState.getOne$('currentUser'); currentUser$: Observable<CurrentUserDto> = this.configState.getOne$('currentUser');
@ -549,21 +551,6 @@ export class NavItemsComponent {
} }
``` ```
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: Open the generated `nav-items.component.html` in `src/app/nav-items` folder and replace the content with the following:
```html ```html

50
docs/en/framework/ui/angular/config-state-service.md

@ -13,11 +13,11 @@ import { ConfigStateService } from '@abp/ng.core';
/* class metadata here */ /* class metadata here */
}) })
class DemoComponent { class DemoComponent {
constructor(private config: ConfigStateService) {} private config = inject(ConfigStateService);
} }
``` ```
You do not have to provide the `ConfigStateService` at module or component/directive level, because it is already **provided in root**. You do not have to provide the `ConfigStateService` at component or directive level, because it is already **provided in root**.
## Get Methods ## Get Methods
@ -35,9 +35,9 @@ You can use the `getAll` or `getAll$` method of `ConfigStateService` to get all
const config = this.config.getAll(); const config = this.config.getAll();
// or // or
this.config.getAll$().subscribe(config => { this.config.getAll$().subscribe((config) => {
// use config here // use config here
}) });
``` ```
### How to Get a Specific Configuration ### How to Get a Specific Configuration
@ -50,9 +50,9 @@ You can use the `getOne` or `getOne$` method of `ConfigStateService` to get a sp
const currentUser = this.config.getOne("currentUser"); const currentUser = this.config.getOne("currentUser");
// or // or
this.config.getOne$("currentUser").subscribe(currentUser => { this.config.getOne$("currentUser").subscribe((currentUser) => {
// use currentUser here // use currentUser here
}) });
``` ```
On occasion, you will probably want to be more specific than getting just the current user. For example, here is how you can get the `tenantId`: On occasion, you will probably want to be more specific than getting just the current user. For example, here is how you can get the `tenantId`:
@ -61,9 +61,9 @@ On occasion, you will probably want to be more specific than getting just the cu
const tenantId = this.config.getDeep("currentUser.tenantId"); const tenantId = this.config.getDeep("currentUser.tenantId");
// or // or
this.config.getDeep$("currentUser.tenantId").subscribe(tenantId => { this.config.getDeep$("currentUser.tenantId").subscribe((tenantId) => {
// use tenantId here // use tenantId here
}) });
``` ```
or by giving an array of keys as parameter: or by giving an array of keys as parameter:
@ -84,9 +84,11 @@ You can use the `getFeature` or `getFeature$` method of `ConfigStateService` to
const enableLdapLogin = this.config.getFeature("Account.EnableLdapLogin"); const enableLdapLogin = this.config.getFeature("Account.EnableLdapLogin");
// or // or
this.config.getFeature$("Account.EnableLdapLogin").subscribe(enableLdapLogin => { this.config
// use enableLdapLogin here .getFeature$("Account.EnableLdapLogin")
}) .subscribe((enableLdapLogin) => {
// use enableLdapLogin here
});
``` ```
> For more information, see the [features document](./features.md). > For more information, see the [features document](./features.md).
@ -98,12 +100,16 @@ You can use the `getSetting` or `getSetting$` method of `ConfigStateService` to
```js ```js
// this.config is instance of ConfigStateService // this.config is instance of ConfigStateService
const twoFactorBehaviour = this.config.getSetting("Abp.Identity.TwoFactor.Behaviour"); const twoFactorBehaviour = this.config.getSetting(
"Abp.Identity.TwoFactor.Behaviour"
);
// or // or
this.config.getSetting$("Abp.Identity.TwoFactor.Behaviour").subscribe(twoFactorBehaviour => { this.config
// use twoFactorBehaviour here .getSetting$("Abp.Identity.TwoFactor.Behaviour")
}) .subscribe((twoFactorBehaviour) => {
// use twoFactorBehaviour here
});
``` ```
> For more information, see the [settings document](./settings.md). > For more information, see the [settings document](./settings.md).
@ -112,7 +118,6 @@ this.config.getSetting$("Abp.Identity.TwoFactor.Behaviour").subscribe(twoFactorB
Please refer to `ApplicationConfigurationDto` type for all the properties you can get with `getOne` and `getDeep`. It can be found in the [models.ts file](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/models.ts#L11). Please refer to `ApplicationConfigurationDto` type for all the properties you can get with `getOne` and `getDeep`. It can be found in the [models.ts file](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/models.ts#L11).
## Set State ## Set State
`ConfigStateService` has a method named `setState` which allow you to set the state value. `ConfigStateService` has a method named `setState` which allow you to set the state value.
@ -120,9 +125,12 @@ Please refer to `ApplicationConfigurationDto` type for all the properties you ca
You can get the application configuration response and set the `ConfigStateService` state value as shown below: You can get the application configuration response and set the `ConfigStateService` state value as shown below:
```js ```js
import {AbpApplicationConfigurationService, ConfigStateService} from '@abp/ng.core'; import { AbpApplicationConfigurationService, ConfigStateService } from '@abp/ng.core';
private abpApplicationConfigurationService = inject(AbpApplicationConfigurationService);
private config = inject(ConfigStateService);
constructor(private abpApplicationConfigurationService: AbpApplicationConfigurationService, private config: ConfigStateService) { constructor() {
this.abpApplicationConfigurationService.get({ includeLocalizationResources: false }).subscribe(config => { this.abpApplicationConfigurationService.get({ includeLocalizationResources: false }).subscribe(config => {
this.config.setState(config); this.config.setState(config);
}) })

25
docs/en/framework/ui/angular/confirmation-service.md

@ -4,7 +4,7 @@ You can use the `ConfirmationService` in @abp/ng.theme.shared package to display
## Getting Started ## Getting Started
You do not have to provide the `ConfirmationService` at module or component level, because it is already **provided in root**. You can inject and start using it immediately in your components, directives, or services. You do not have to provide the `ConfirmationService` at component level, because it is already **provided in root**. You can inject and start using it immediately in your components, directives, or services.
```js ```js
import { ConfirmationService } from '@abp/ng.theme.shared'; import { ConfirmationService } from '@abp/ng.theme.shared';
@ -129,24 +129,25 @@ this.confirmation.clear();
### How to Change Icons of The Confirmation Popup ### How to Change Icons of The Confirmation Popup
You can change icons with the `withConfirmationIcon()` method of `provideAbpThemeShared` function in the app.module.ts. The changes will affect all confirmation popup in the project. You can change icons with the `withConfirmationIcon()` method inside `provideAbpThemeShared` function in the app.config.ts. The changes will affect all confirmation popup in the project.
```ts ```ts
import { provideAbpThemeShared, withConfirmationIcon } from '@abp/ng.theme.shared'; import { provideAbpThemeShared, withConfirmationIcon } from '@abp/ng.theme.shared';
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
// ... // ...
provideAbpThemeShared(withConfirmationIcon({ provideAbpThemeShared(
info: 'fa fa-info-circle', withConfirmationIcon({
success: 'fa fa-check-circle', info: 'fa fa-info-circle',
warning: 'fa fa-exclamation-triangle', success: 'fa fa-check-circle',
error: 'fa fa-times-circle', warning: 'fa fa-exclamation-triangle',
default: 'fa fa-question-circle', error: 'fa fa-times-circle',
})), default: 'fa fa-question-circle',
})
),
], ],
}) };
export class AppModule {}
``` ```
## API ## API

16
docs/en/framework/ui/angular/data-table-column-extensions.md

@ -14,7 +14,7 @@ In this example, we will add a "Name" column and display the value of the `name`
### Step 1. Create Entity Prop Contributors ### Step 1. Create Entity Prop Contributors
The following code prepares a constant named `identityEntityPropContributors`, ready to be imported and used in your root module: The following code prepares a constant named `identityEntityPropContributors`, ready to be imported and used in your root application configuration:
```js ```js
// src/app/entity-prop-contributors.ts // src/app/entity-prop-contributors.ts
@ -52,22 +52,22 @@ The list of props, conveniently named as `propList`, is a **doubly linked list**
### Step 2. Import and Use Entity Prop Contributors ### Step 2. Import and Use Entity Prop Contributors
Import `identityEntityPropContributors` in your routing module and pass it to the static `forLazy` method of `IdentityModule` as seen below: Import `identityEntityPropContributors` in your routing configuration and pass it to the static `createRoutes` method for `identity` route as seen below:
```js ```js
// src/app/app-routing.module.ts // src/app/app.routes.ts
// other imports // other imports
import { identityEntityPropContributors } from './entity-prop-contributors'; import { identityEntityPropContributors } from './entity-prop-contributors';
const routes: Routes = [ export const APP_ROUTES: Routes = [
// other routes // other routes
{ {
path: 'identity', path: 'identity',
loadChildren: () => loadChildren: () =>
import('@abp/ng.identity').then(m => import('@abp/ng.identity').then(c =>
m.IdentityModule.forLazy({ c.createRoutes({
entityPropContributors: identityEntityPropContributors, entityPropContributors: identityEntityPropContributors,
}) })
), ),
@ -77,7 +77,7 @@ const routes: Routes = [
]; ];
``` ```
That is it, `nameProp` entity prop will be added, and you will see the "Name" column next to the usernames on the grid in the users page (`UsersComponent`) of the `IdentityModule`. That is it, `nameProp` entity prop will be added, and you will see the "Name" column next to the usernames on the grid in the users page (`UsersComponent`) of the `identity` package.
## How to Render Custom HTML in Cells ## How to Render Custom HTML in Cells
@ -318,7 +318,7 @@ export function reorderUserContributors(
### EntityPropContributorCallback\<R = any\> ### EntityPropContributorCallback\<R = any\>
`EntityPropContributorCallback` is the type that you can pass as entity prop contributor callbacks to static `forLazy` methods of the modules. `EntityPropContributorCallback` is the type that you can pass as entity prop contributor callbacks to static `createRoutes` methods of the packages.
```js ```js
export function isLockedOutPropContributor( export function isLockedOutPropContributor(

18
docs/en/framework/ui/angular/dynamic-form-extensions.md

@ -15,7 +15,7 @@ In this example, we will add a "Date of Birth" field in the user management page
### Step 1. Create Form Prop Contributors ### Step 1. Create Form Prop Contributors
The following code prepares two constants named `identityCreateFormPropContributors` and `identityEditFormPropContributors`, ready to be imported and used in your root module: The following code prepares two constants named `identityCreateFormPropContributors` and `identityEditFormPropContributors`, ready to be imported and used in your root application configuration:
```js ```js
// src/app/form-prop-contributors.ts // src/app/form-prop-contributors.ts
@ -57,10 +57,10 @@ The list of props, conveniently named as `propList`, is a **doubly linked list**
### Step 2. Import and Use Form Prop Contributors ### Step 2. Import and Use Form Prop Contributors
Import `identityCreateFormPropContributors` and `identityEditFormPropContributors` in your routing module and pass it to the static `forLazy` method of `IdentityModule` as seen below: Import `identityCreateFormPropContributors` and `identityEditFormPropContributors` in your routing configuration and pass it to the static `createRoutes` method for `identity` route as seen below:
```js ```js
// src/app/app-routing.module.ts // src/app/app.routes.ts
// other imports // other imports
import { import {
@ -68,14 +68,14 @@ import {
identityEditFormPropContributors, identityEditFormPropContributors,
} from './form-prop-contributors'; } from './form-prop-contributors';
const routes: Routes = [ export const APP_ROUTES: Routes = [
// other routes // other routes
{ {
path: 'identity', path: 'identity',
loadChildren: () => loadChildren: () =>
import('@abp/ng.identity').then(m => import('@abp/ng.identity').then(c =>
m.IdentityModule.forLazy({ c.createRoutes({
createFormPropContributors: identityCreateFormPropContributors, createFormPropContributors: identityCreateFormPropContributors,
editFormPropContributors: identityEditFormPropContributors, editFormPropContributors: identityEditFormPropContributors,
}) })
@ -86,7 +86,7 @@ const routes: Routes = [
]; ];
``` ```
That is it, `birthdayProp` form prop will be added, and you will see the datepicker for the "Date of Birth" field right before the "Email address" in the forms of the users page in the `IdentityModule`. That is it, `birthdayProp` form prop will be added, and you will see the datepicker for the "Date of Birth" field right before the "Email address" in the forms of the users page in the `identity` package.
## Object Extensions ## Object Extensions
@ -309,7 +309,7 @@ export function reorderUserContributors(
### CreateFormPropContributorCallback\<R = any\> ### CreateFormPropContributorCallback\<R = any\>
`CreateFormPropContributorCallback` is the type that you can pass as **create form** prop contributor callbacks to static `forLazy` methods of the modules. `CreateFormPropContributorCallback` is the type that you can pass as **create form** prop contributor callbacks to static `createRoutes` methods of the packages.
```js ```js
export function myPropCreateContributor( export function myPropCreateContributor(
@ -326,7 +326,7 @@ export const identityCreateFormPropContributors = {
### EditFormPropContributorCallback\<R = any\> ### EditFormPropContributorCallback\<R = any\>
`EditFormPropContributorCallback` is the type that you can pass as **edit form** prop contributor callbacks to static `forLazy` methods of the modules. `EditFormPropContributorCallback` is the type that you can pass as **edit form** prop contributor callbacks to static `createRoutes` methods of the packages.
```js ```js
export function myPropEditContributor( export function myPropEditContributor(

49
docs/en/framework/ui/angular/ellipsis-directive.md

@ -5,47 +5,26 @@ Text inside an HTML element can be truncated easily with an ellipsis by using CS
## Getting Started ## Getting Started
In order to use the `EllipsisDirective` in an HTML template, the **`ThemeSharedModule`** should be imported into your module like this: In order to use the `EllipsisDirective` in an HTML template, it should be imported in your component. The selector of directive is **`abpEllipsis`**. By adding the `abpEllipsis` attribute to an HTML element, you can activate the `EllipsisDirective` for the HTML element.
```js ```js
// ... // ...
import { ThemeSharedModule } from '@abp/ng.theme.shared'; import { EllipsisDirective } from '@abp/ng.theme.shared';
@NgModule({ @Component({
//... //...
imports: [..., ThemeSharedModule], imports: [EllipsisDirective],
template: `
<p abpEllipsis>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Laboriosam commodi quae aspernatur,
corporis velit et suscipit id consequuntur amet minima expedita cum reiciendis dolorum
cupiditate? Voluptas eaque voluptatum odio deleniti quo vel illum nemo accusamus nulla ratione
impedit dolorum expedita necessitatibus fugiat ullam beatae, optio eum cupiditate ducimus
architecto.
</p>
`
}) })
export class MyFeatureModule {} export class SampleComponent {}
```
or **if you would not like to import** the `ThemeSharedModule`, you can import the **`EllipsisModule`** as shown below:
```js
// ...
import { EllipsisModule } from '@abp/ng.theme.shared';
@NgModule({
//...
imports: [..., EllipsisModule],
})
export class MyFeatureModule {}
```
## Usage
The `EllipsisDirective` is very easy to use. The directive's selector is **`abpEllipsis`**. By adding the `abpEllipsis` attribute to an HTML element, you can activate the `EllipsisDirective` for the HTML element.
See an example usage:
```html
<p abpEllipsis>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Laboriosam commodi quae aspernatur,
corporis velit et suscipit id consequuntur amet minima expedita cum reiciendis dolorum
cupiditate? Voluptas eaque voluptatum odio deleniti quo vel illum nemo accusamus nulla ratione
impedit dolorum expedita necessitatibus fugiat ullam beatae, optio eum cupiditate ducimus
architecto.
</p>
``` ```
The `abpEllipsis` attribute has been added to the `<p>` element that containing very long text inside to activate the `EllipsisDirective`. The `abpEllipsis` attribute has been added to the `<p>` element that containing very long text inside to activate the `EllipsisDirective`.

93
docs/en/framework/ui/angular/entity-action-extensions.md

@ -14,7 +14,7 @@ In this example, we will add a "Click Me!" action and alert the current row's `u
### Step 1. Create Entity Action Contributors ### Step 1. Create Entity Action Contributors
The following code prepares a constant named `identityEntityActionContributors`, ready to be imported and used in your root module: The following code prepares a constant named `identityEntityActionContributors`, ready to be imported and used in your root application configuration:
```ts ```ts
// src/app/entity-action-contributors.ts // src/app/entity-action-contributors.ts
@ -49,22 +49,22 @@ The list of actions, conveniently named as `actionList`, is a **doubly linked li
### Step 2. Import and Use Entity Action Contributors ### Step 2. Import and Use Entity Action Contributors
Import `identityEntityActionContributors` in your routing module and pass it to the static `forLazy` method of `IdentityModule` as seen below: Import `identityEntityActionContributors` in your routing configuration and pass it to the static `configureRoutes` method for `identity` routes as seen below:
```js ```js
// src/app/app-routing.module.ts // src/app/app.routes.ts
// other imports // other imports
import { identityEntityActionContributors } from './entity-action-contributors'; import { identityEntityActionContributors } from './entity-action-contributors';
const routes: Routes = [ export const APP_ROUTES: Routes = [
// other routes // other routes
{ {
path: 'identity', path: 'identity',
loadChildren: () => loadChildren: () =>
import('@abp/ng.identity').then(m => import('@abp/ng.identity').then(c =>
m.IdentityModule.forLazy({ c.createRoutes({
entityActionContributors: identityEntityActionContributors, entityActionContributors: identityEntityActionContributors,
}) })
), ),
@ -74,11 +74,11 @@ const routes: Routes = [
]; ];
``` ```
That is it, `alertUserName` entity action will be added as the last action on the grid dropdown in the "Users" page (`UsersComponent`) of the `IdentityModule`. That is it, `alertUserName` entity action will be added as the last action on the grid dropdown in the "Users" page (`UsersComponent`) of the `identity` package.
## How to Place a Custom Modal and Trigger It by Entity Actions ## How to Place a Custom Modal and Trigger It by Entity Actions
Let's employ dependency injection to extend the functionality of `IdentityModule` and add a quick view action for the User entity. We will take a lazy-loaded approach. Let's employ dependency injection to extend the functionality of `identity` package and add a quick view action for the User entity. We will take a lazy-loaded approach.
<img alt="Entity Action Extension Example: Custom Modal" src="./images/entity-action-extensions---custom-modal.gif" width="800px" style="max-width:100%"> <img alt="Entity Action Extension Example: Custom Modal" src="./images/entity-action-extensions---custom-modal.gif" width="800px" style="max-width:100%">
@ -117,16 +117,27 @@ Let's employ dependency injection to extend the functionality of `IdentityModule
}; };
``` ```
3. Create a parent component to the identity module. 3. Create a parent component to the identity package.
```js ```js
// src/app/identity-extended/identity-extended.component.ts // src/app/identity-extended/identity-extended.component.ts
import { IdentityUserDto } from '@abp/ng.identity'; import { LocalizationPipe } from '@abp/ng.core';
import { IdentityUserDto } from '@abp/ng.identity/proxy';
import { ModalCloseDirective, ModalComponent } from '@abp/ng.theme.shared';
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({ @Component({
selector: 'app-identity-extended', selector: 'app-identity-extended',
templateUrl: './identity-extended.component.html', templateUrl: './identity-extended.component.html',
imports: [
CommonModule,
ModalComponent,
RouterOutlet,
LocalizationPipe,
ModalCloseDirective
]
}) })
export class IdentityExtendedComponent { export class IdentityExtendedComponent {
isUserQuickViewVisible: boolean; isUserQuickViewVisible: boolean;
@ -184,55 +195,47 @@ Let's employ dependency injection to extend the functionality of `IdentityModule
</abp-modal> </abp-modal>
``` ```
5. Add a module for the component and load `IdentityModule` as seen below: 5. Add a routing configuration for the component as seen below:
```js ```js
// src/app/identity-extended/identity-extended.module.ts // src/app/identity-extended/identity-extended.routes.ts
import { CoreModule } from '@abp/ng.core'; import { Routes } from '@angular/router';
import { IdentityModule } from '@abp/ng.identity';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { identityEntityActionContributors } from './entity-action-contributors';
import { IdentityExtendedComponent } from './identity-extended.component'; import { IdentityExtendedComponent } from './identity-extended.component';
import { identityEntityActionContributors } from './entity-action-contributors';
@NgModule({ export const createExtendedIdentityRoutes = (): Routes => [
imports: [ {
CoreModule, path: '',
ThemeSharedModule, component: IdentityExtendedComponent,
RouterModule.forChild([ children: [
{ {
path: '', path: '',
component: IdentityExtendedComponent, loadChildren: () =>
children: [ import('@abp/ng.identity').then(c =>
{ c.createRoutes({
path: '', entityActionContributors: identityEntityActionContributors,
loadChildren: () => }),
IdentityModule.forLazy({ ),
entityActionContributors: identityEntityActionContributors,
}),
},
],
}, },
]), ],
], },
declarations: [IdentityExtendedComponent], ];
})
export class IdentityExtendedModule {}
``` ```
6. Load `IdentityExtendedModule` instead of `IdentityModule` in your root routing module. 6. Use `createExtendedIdentityRoutes` instead of the `createRoutes` function in your root routing configuration.
Since the routes are already lazily loaded in the `createExtendedIdentityRoutes` function, you can directly use its children array to avoid an unnecessary additional lazy-loading call.
```js ```js
// src/app/app-routing.module.ts // src/app/app.routes.ts
const routes: Routes = [ export const APP_ROUTES: Routes = [
// other routes // other routes
{ {
path: 'identity', path: 'identity',
loadChildren: () => children: [
import('./identity-extended/identity-extended.module') ...createExtendedIdentityRoutes()
.then(m => m.IdentityExtendedModule), ],
}, },
// other routes // other routes
@ -387,7 +390,7 @@ export function reorderUserContributors(
### EntityActionContributorCallback\<R = any\> ### EntityActionContributorCallback\<R = any\>
`EntityActionContributorCallback` is the type that you can pass as entity action contributor callbacks to static `forLazy` methods of the modules. `EntityActionContributorCallback` is the type that you can pass as entity action contributor callbacks to static `createRoutes` methods of the packages.
```js ```js
// lockUserContributor should have EntityActionContributorCallback<IdentityUserDto> type // lockUserContributor should have EntityActionContributorCallback<IdentityUserDto> type

33
docs/en/framework/ui/angular/entity-filters.md

@ -5,27 +5,9 @@ Every CRUD page includes some sort of inputs to filter the listed data. Some of
## Setup ## Setup
The components are in the _@volo/abp.commercial.ng.ui_ package, which is included in the ABP templates. So, as long as your project is a product of these templates and unless you delete the package, you have access to the entity filter components. The components are in the _@volo/abp.commercial.ng.ui_ package, which is included in the ABP templates. So, as long as your project is a product of these templates and unless you delete the package, you have access to the entity filter components.
You can either import the `CommercialUiModule` which contains other components as well as `AdvancedEntityFilters` or you can directly import the `AdvancedEntityFiltersModule` if you do not need other components. Here is how you import them in your Angular module:
Advanced entity filters are composed of several components: `AdvancedEntityFiltersComponent`, `AdvancedEntityFiltersToggleComponent`, `AdvancedEntityFiltersFormComponent`, and `AdvancedEntityFiltersAboveSearchComponent`. You can use these components directly by importing them into your standalone components.
```javascript
import {
CommercialUiModule,
AdvancedEntityFiltersModule,
} from "@volo/abp.commercial.ng.ui";
@NgModule({
imports: [
// other imports
CommercialUiModule,
// OR
AdvancedEntityFiltersModule,
],
// rest of the module metadata
})
export class YourModule {}
```
## Usage ## Usage
@ -33,7 +15,7 @@ Let's take a look at the `Users` page from the `Identity` module.
![ABP Angular UI Users Page with Advanced Entity Filters](./images/angular-advanced-entity-filters.png) ![ABP Angular UI Users Page with Advanced Entity Filters](./images/angular-advanced-entity-filters.png)
As shown in the screenshot, `abp-advanced-entity-filters` usually contain two parts, an entity filter (common among entities), i.e. `abp-entity-filter`, and entity-specific filters which are encapsulated within the `abp-advanced-entity-filters-form` component. As shown in the screenshot, `abp-advanced-entity-filters` usually contain two parts, an entity filter (common among entities), i.e. `abp-entity-filter`, and entity-specific filters which are encapsulated within the `abp-advanced-entity-filters-form` component. You will need to add `AdvancedEntityFiltersComponent` and `AdvancedEntityFiltersFormComponent` to your components' imports array to be able to use them.
`users.component.html` `users.component.html`
@ -72,7 +54,7 @@ As shown in the screenshot, `abp-advanced-entity-filters` usually contain two pa
</abp-advanced-entity-filters> </abp-advanced-entity-filters>
``` ```
The `abp-advanced-entity-filters` already contains the `abp-entity-filter` component so you do not need to pass it. However, the `abp-entity-filter` component needs an instance of `ListService` which is usually stored in the `list` field of the page. You can also change the placeholder of the component via `entityFilterPlaceholder` input which is passed into the `abpLocalization` pipe so that it uses the translated text. Default is `'AbpUi::PagerSearch'` The `abp-advanced-entity-filters` already contains the `abp-entity-filter` component so you do not need to pass it. However, the `abp-entity-filter` component needs an instance of `ListService` which is usually stored in the `list` field of the page. You can also change the placeholder of the component via `entityFilterPlaceholder` input which is passed into the `abpLocalization` pipe so that it uses the translated text. The default is `'AbpUi::PagerSearch'`
E.g E.g
@ -100,8 +82,7 @@ E.g.
Let's remove `form` from the `Users` page Let's remove `form` from the `Users` page
```html ```html
<abp-advanced-entity-filters [list]="list" localizationSourceName="AbpIdentity"> <abp-advanced-entity-filters [list]="list" localizationSourceName="AbpIdentity" />
</abp-advanced-entity-filters>
``` ```
![ABP Angular UI Users Page with Advanced Entity Filters without form](./images/angular-advanced-entity-filters-without-form.png) ![ABP Angular UI Users Page with Advanced Entity Filters without form](./images/angular-advanced-entity-filters-without-form.png)
@ -122,7 +103,7 @@ E.g.
![ABP Angular UI Users Page with Advanced Entity Filters with form](./images/angular-advanced-entity-filters-with-form.png) ![ABP Angular UI Users Page with Advanced Entity Filters with form](./images/angular-advanced-entity-filters-with-form.png)
Last but not least, if you need to render some content above the `abp-entity-filter` component, you can use the `abp-advanced-entity-filters-above-search`. Last but not least, if you need to render some content above the `abp-entity-filter` component, you can use the `abp-advanced-entity-filters-above-search`. This time, you will need to add `AdvancedEntityFiltersComponent`, `AdvancedEntityFiltersFormComponent`, and `AdvancedEntityFiltersAboveSearchComponent` to the imports' array of your component.
E.g. E.g.

26
docs/en/framework/ui/angular/environment.md

@ -101,22 +101,28 @@ export interface RemoteEnv {
- `method`: HTTP method to be used when retrieving environment config. Default: `GET` - `method`: HTTP method to be used when retrieving environment config. Default: `GET`
- `headers`: If extra headers are needed for the request, it can be set through this field. - `headers`: If extra headers are needed for the request, it can be set through this field.
## Provide Environment Variable to Core Module ## Configure Core Provider with Environment
`environment` variable comes from angular host application. `environment` variable comes from angular host application.
```js ```js
import { environment } from '../environments/environment'; import { environment } from '../environments/environment';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
//...other imports ...
CoreModule.forRoot({ provideAbpCore(
environment withOptions({
}), environment,
] ...
}) })
),
...
],
};
``` ```
## EnvironmentService ## EnvironmentService
` EnvironmentService` is a singleton service, i.e. provided in root level of your application, and keeps the environment in the internal store. ` EnvironmentService` is a singleton service, i.e. provided in root level of your application, and keeps the environment in the internal store.
@ -132,7 +138,7 @@ import { EnvironmentService } from '@abp/ng.core';
/* class metadata here */ /* class metadata here */
}) })
class DemoComponent { class DemoComponent {
constructor(private environment: EnvironmentService) {} private environment = inject(EnvironmentService);
} }
``` ```

4
docs/en/framework/ui/angular/extensions-overall.md

@ -21,8 +21,8 @@ Using [ngx-datatable](https://github.com/swimlane/ngx-datatable) in extensible t
[actionsColumnWidth]="38" [actionsColumnWidth]="38"
[actionsTemplate]="customAction" [actionsTemplate]="customAction"
[list]="list" [list]="list"
(tableActivate)="onTableSelect($event)" > (tableActivate)="onTableSelect($event)"
</abp-extensible-table> />
```` ````
* ` actionsText : ` ** Column name of action column. **Type** : string * ` actionsText : ` ** Column name of action column. **Type** : string

41
docs/en/framework/ui/angular/feature-libraries.md

@ -4,10 +4,10 @@ ABP has an ever-growing number of feature modules and [introducing a new one](..
## Feature Library Content ## Feature Library Content
Each library has at least two modules: Each library has at least two key elements:
1. The main module contains all components, services, types, enums, etc. to deliver the required UI when the feature is loaded. From here on, we will refer to these modules as **"feature module"**. 1. A **feature definition** that encapsulates all components, services, types, enums, and routing logic needed to deliver the UI for a given feature. With standalone structure, this is often expressed through a `routes.ts` file and associated components, and we will refer to this as the **"feature structure"**.
2. There is also a **"config module"** per library which helps us configure applications to run these modules or make them accessible. 2. A **configuration provider** that exposes setup logic, such as `provideMyProjectNameConfig()` functions or environment, specific tokens—allowing the feature to be initialized or integrated differently across applications. We will refer to this as the **configuration structure**.
## How to Add a Feature Library to Your Project ## How to Add a Feature Library to Your Project
@ -37,55 +37,46 @@ yarn add @abp/ng.identity
> Identity is used just as an example. If you have initiated your project with ABP CLI or ABP Suite, the identity library will already be installed and configured in your project. > Identity is used just as an example. If you have initiated your project with ABP CLI or ABP Suite, the identity library will already be installed and configured in your project.
### 2. Import the Config Module ### 2. Import the Configuration Provider
As of ABP v3.0, every lazy-loaded module has a config module available via a secondary entry point on the same package. Importing them in your root module looks like this: As of ABP v9.3, every lazy-loaded route has a config provider available via a secondary entry point on the same package. Importing them in your root configuration looks like this:
```ts ```ts
import { provideIdentityConfig } from "@abp/ng.identity/config"; import { provideIdentityConfig } from "@abp/ng.identity/config";
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
// other imports // other providers
provideIdentityConfig(), provideIdentityConfig(),
], ],
// providers, declarations, and bootstrap };
})
export class AppModule {}
``` ```
We need the config modules for actions required before feature modules are loaded (lazily). For example, the above import configures the menu to display links to identity pages. We need the config providers for actions required before feature structure is loaded (lazily). For example, the above import configures the menu to display links to identity pages.
Furthermore, depending on the library, the `.forRoot` static method may receive some options that configure how the feature works. Furthermore, depending on the library, the `.createRoutes` static method may receive some options that configure how the feature works.
### 3. Import the Feature Module ### 3. Import the Feature Definition
Finally, the feature module should be [loaded lazily via Angular router](https://angular.io/guide/lazy-loading-ngmodules). If you open the `/src/app/app-routing.module.ts` file, you should see `IdentityModule` is loaded exactly as follows: Finally, the feature structure should be [loaded lazily via Angular router](https://angular.dev/reference/migrations/route-lazy-loading). In a standalone setup, routing is typically defined in a `app.routes.ts` file, and feature modules are replaced with route-level feature definitions. You should see the identity routes configured like this:
```js ```js
import { NgModule } from "@angular/core"; import { Routes } from "@angular/router";
import { RouterModule, Routes } from "@angular/router";
const routes: Routes = [ const APP_ROUTES: Routes = [
// other routes // other routes
{ {
path: "identity", path: "identity",
loadChildren: () => loadChildren: () =>
import("@abp/ng.identity").then((m) => m.IdentityModule.forLazy()), import("@abp/ng.identity").then((m) => m.createRoutes()),
}, },
// other routes // other routes
]; ];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
``` ```
When you load the identity feature like this, the "Users" page, for example, will have a route path of `/identity/users`. <sup id="a-modify-route">[1](#f-modify-route)</sup> When you load the identity feature like this, the "Users" page, for example, will have a route path of `/identity/users`. <sup id="a-modify-route">[1](#f-modify-route)</sup>
Depending on the library, the `.forLazy` static method may also receive some options that configure how the feature works. Depending on the library, the `.createRoutes` static method may also receive some options that configure how the feature works.
--- ---

64
docs/en/framework/ui/angular/form-validation.md

@ -6,31 +6,31 @@ Reactive forms in ABP Angular UI are validated by [ngx-validate](https://www.npm
## How to Add New Error Messages ## How to Add New Error Messages
You can add a new error message by passing validation options to the `withValidationBluePrint` method of `provideAbpThemeShared` function in your root module. You can add a new error message by passing validation options to the `withValidationBluePrint` method inside `provideAbpThemeShared` function in your root application configuration.
```ts ```ts
import { provideAbpThemeShared, withValidationBluePrint } from '@abp/ng.theme.shared'; import { provideAbpThemeShared, withValidationBluePrint } from '@abp/ng.theme.shared';
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
// ...
provideAbpThemeShared( provideAbpThemeShared(
withValidationBluePrint({ withValidationBluePrint({
uniqueUsername: "::AlreadyExists[{%{{{ username }}}%}]" uniqueUsername: "::AlreadyExists[{%{{{ username }}}%}]"
}) })
), ),
... // ...
], ],
}) };
export class AppModule {}
``` ```
Alternatively, you may provide the `VALIDATION_BLUEPRINTS` token directly in your root module. Please do not forget to spread `DEFAULT_VALIDATION_BLUEPRINTS`. Otherwise, built-in ABP validation messages will not work. Alternatively, you may provide the `VALIDATION_BLUEPRINTS` token directly in your root configuration. Please do not forget to spread `DEFAULT_VALIDATION_BLUEPRINTS`. Otherwise, built-in ABP validation messages will not work.
```js ```js
import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core"; import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core";
import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared"; import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared";
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
{ {
provide: VALIDATION_BLUEPRINTS, provide: VALIDATION_BLUEPRINTS,
@ -42,10 +42,7 @@ import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared";
// other providers // other providers
], ],
};
// rest of the module metadata
})
export class AppModule {}
``` ```
When a [validator](https://angular.io/guide/form-validation#defining-custom-validators) or an [async validator](https://angular.io/guide/form-validation#creating-asynchronous-validators) returns an error with the key given to the error blueprints (`uniqueUsername` here), the validation library will be able to display an error message after localizing according to the given key and interpolation params. The result will look like this: When a [validator](https://angular.io/guide/form-validation#defining-custom-validators) or an [async validator](https://angular.io/guide/form-validation#creating-asynchronous-validators) returns an error with the key given to the error blueprints (`uniqueUsername` here), the validation library will be able to display an error message after localizing according to the given key and interpolation params. The result will look like this:
@ -61,7 +58,7 @@ In this example;
## How to Change Existing Error Messages ## How to Change Existing Error Messages
You can overwrite an existing error message by passing validation options to the `ThemeSharedModule` in your root module. Let's imagine you have a custom localization resource for required inputs. You can overwrite an existing error message by passing validation options to the `provideAbpThemeShared` in your root application configuration. Let's imagine you have a custom localization resource for required inputs.
```json ```json
"RequiredInput": "Oops! We need this input." "RequiredInput": "Oops! We need this input."
@ -72,24 +69,26 @@ To use this instead of the built-in required input message, all you need to do i
```ts ```ts
import { provideAbpThemeShared, withValidationBluePrint } from '@abp/ng.theme.shared'; import { provideAbpThemeShared, withValidationBluePrint } from '@abp/ng.theme.shared';
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
provideAbpThemeShared(withValidationBluePrint({ // ...
required: "::RequiredInput", provideAbpThemeShared(
})), withValidationBluePrint({
... required: "::RequiredInput",
})
),
// ...
], ],
}) };
export class AppModule {}
``` ```
Alternatively, you may provide the `VALIDATION_BLUEPRINTS` token directly in your root module. Please do not forget to spread `DEFAULT_VALIDATION_BLUEPRINTS`. Otherwise, built-in ABP validation messages will not work. Alternatively, you may provide the `VALIDATION_BLUEPRINTS` token directly in your root app configuration. Please do not forget to spread `DEFAULT_VALIDATION_BLUEPRINTS`. Otherwise, built-in ABP validation messages will not work.
```js ```js
import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core"; import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core";
import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared"; import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared";
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
{ {
provide: VALIDATION_BLUEPRINTS, provide: VALIDATION_BLUEPRINTS,
@ -101,10 +100,7 @@ import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared";
// other providers // other providers
], ],
};
// rest of the module metadata
})
export class AppModule {}
``` ```
The error message will look like this: The error message will look like this:
@ -134,17 +130,20 @@ Validation works on any element or component with a `formControl` or `formContro
First, build a custom error component. Extending the existing `ValidationErrorComponent` would make it easier. First, build a custom error component. Extending the existing `ValidationErrorComponent` would make it easier.
```js ```js
import { LocalizationPipe } from "@abp/ng.core";
import { ValidationErrorComponent } from "@abp/ng.theme.basic"; import { ValidationErrorComponent } from "@abp/ng.theme.basic";
import { CommonModule } from "@angular/common";
import { ChangeDetectionStrategy, Component } from "@angular/core"; import { ChangeDetectionStrategy, Component } from "@angular/core";
@Component({ @Component({
selector: "app-validation-error", selector: "app-validation-error",
imports:[CommonModule, LocalizationPipe],
template: ` template: `
<div <div
class="font-weight-bold font-italic px-1 invalid-feedback" class="font-weight-bold font-italic px-1 invalid-feedback"
*ngFor="let error of abpErrors; trackBy: trackByFn" *ngFor="let error of abpErrors; trackBy: trackByFn"
> >
{%{{{ error.message | abpLocalization: error.interpoliteParams }}}%} {{ error.message | abpLocalization: error.interpoliteParams }}
</div> </div>
`, `,
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
@ -152,18 +151,12 @@ import { ChangeDetectionStrategy, Component } from "@angular/core";
export class ErrorComponent extends ValidationErrorComponent {} export class ErrorComponent extends ValidationErrorComponent {}
``` ```
Then, declare and provide it in your root module. Then, provide it in your root configuration.
```js ```js
import { VALIDATION_ERROR_TEMPLATE } from "@ngx-validate/core"; import { VALIDATION_ERROR_TEMPLATE } from "@ngx-validate/core";
@NgModule({ export const appConfig: ApplicationConfig = {
// rest of the module metadata
declarations: [
// other declarables
ErrorComponent,
],
providers: [ providers: [
// other providers // other providers
{ {
@ -171,8 +164,7 @@ import { VALIDATION_ERROR_TEMPLATE } from "@ngx-validate/core";
useValue: ErrorComponent, useValue: ErrorComponent,
}, },
], ],
}) };
export class AppModule {}
``` ```
The error message will be bold and italic now: The error message will be bold and italic now:

59
docs/en/framework/ui/angular/http-error-handling.md

@ -5,25 +5,25 @@
ABP offers a configurations for errors handling like below ABP offers a configurations for errors handling like below
```ts ```ts
import { ThemeSharedModule } from '@abp/ng.theme.shared'; //app.config.ts
import { MyCustomRouteErrorComponent } from './my-custom-route.component'; import { provideAbpThemeShared } from '@abp/ng.theme.shared';
import { CustomErrorComponent } from './custom-error.component';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
ThemeSharedModule.forRoot({ provideAbpThemeShared(
httpErrorConfig: { withHttpErrorConfig({
skipHandledErrorCodes: [403], skipHandledErrorCodes: [403],
errorScreen: { errorScreen: {
forWhichErrors: [404],
component: CustomErrorComponent, component: CustomErrorComponent,
hideCloseIcon: false forWhichErrors: [404],
} hideCloseIcon: false,
} },
}), }),
... ),
], ],
}) };
export class AppModule {}
``` ```
- `ErrorScreenErrorCodes` the error codes that you can pass to `skipHandledErrorCodes` and `forWhichErrors`. - `ErrorScreenErrorCodes` the error codes that you can pass to `skipHandledErrorCodes` and `forWhichErrors`.
@ -67,27 +67,24 @@ export function handleHttpErrors(injector: Injector, httpError: HttpErrorRespons
return of(httpError); return of(httpError);
} }
// app.module.ts // app.config.ts
import { Error404Component } from './error404/error404.component'; import { Error404Component } from './error404/error404.component';
import { handleHttpErrors } from './http-error-handling'; import { handleHttpErrors } from './http-error-handling';
import { HTTP_ERROR_HANDLER, ... } from '@abp/ng.theme.shared'; import { HTTP_ERROR_HANDLER, ... } from '@abp/ng.theme.shared';
@NgModule({ export const appConfig: ApplicationConfig = {
// ...
providers: [ providers: [
// ... ...
{ provide: HTTP_ERROR_HANDLER, useValue: handleHttpErrors } { provide: HTTP_ERROR_HANDLER, useValue: handleHttpErrors },
...
], ],
declarations: [ };
//...
Error404Component],
})
export class AppModule {}
``` ```
In the example above: In the example above:
- Created a function named `handleHttpErrors` and defined as value of the `HTTP_ERROR_HANDLER` provider in app.module. After this, the function executes when an HTTP error occurs. - Created a function named `handleHttpErrors` and defined as value of the `HTTP_ERROR_HANDLER` provider in `app.config.ts`. After this, the function executes when an HTTP error occurs.
- 400 bad request errors is handled. When a 400 error occurs. - 400 bad request errors is handled. When a 400 error occurs.
- Since `of(httpError)` is returned at bottom of the `handleHttpErrors`, the `ErrorHandler` will handle the HTTP errors except 400 and 404 errors. - Since `of(httpError)` is returned at bottom of the `handleHttpErrors`, the `ErrorHandler` will handle the HTTP errors except 400 and 404 errors.
@ -195,22 +192,20 @@ export class MyCustomErrorHandlerService
```ts ```ts
// app.module.ts // app.config.ts
import { CUSTOM_ERROR_HANDLERS, ... } from '@abp/ng.theme.shared'; import { CUSTOM_ERROR_HANDLERS, ... } from '@abp/ng.theme.shared';
import { MyCustomErrorHandlerService } from './custom-error-handler.service'; import { MyCustomErrorHandlerService } from './custom-error-handler.service';
@NgModule({ export const appConfig: ApplicationConfig = {
// ...
providers: [ providers: [
// ... //...
{ {
provide: CUSTOM_ERROR_HANDLERS, provide: CUSTOM_ERROR_HANDLERS,
useExisting: MyCustomErrorHandlerService, useExisting: MyCustomErrorHandlerService,
multi: true, multi: true,
} }
] ],
}) };
export class AppModule {}
``` ```
In the example above: In the example above:

BIN
docs/en/framework/ui/angular/images/quick-start---root-folder-structure.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 70 KiB

BIN
docs/en/framework/ui/angular/images/quick-start---source-folder-structure.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 73 KiB

1
docs/en/framework/ui/angular/list-service.md

@ -151,7 +151,6 @@ import { Component, inject } from '@angular/core';
import { BookDto, BooksService } from './books.service'; import { BookDto, BooksService } from './books.service';
@Component({ @Component({
standalone: true,
selector: 'app-books', selector: 'app-books',
templateUrl: './books.component.html', templateUrl: './books.component.html',
providers: [ListService, BooksService], providers: [ListService, BooksService],

17
docs/en/framework/ui/angular/loading-directive.md

@ -6,23 +6,24 @@ You may want to block a part of the UI and show a spinner for a while; the `Load
## Getting Started ## Getting Started
In order to use the `LoadingDirective` in an HTML template, the **`ThemeSharedModule`** should be imported into your module like this: In order to use the `LoadingDirective` in an HTML template, it should be imported into your component like this:
```js ```js
// ... // ...
import { ThemeSharedModule } from '@abp/ng.theme.shared'; import { LoadingDirective } from '@abp/ng.theme.shared';
@NgModule({ @Component({
//... // ...
imports: [..., ThemeSharedModule], imports: [ LoadingDirective ]
// ...
}) })
export class MyFeatureModule {} export class SampleComponent {}
``` ```
## Usage ## Usage
The `LoadingDirective` is easy to use. The directive's selector is **`abpLoading`**. By adding the `abpLoading` attribute to an HTML element, you can activate the `LoadingDirectiveective` for the HTML element when the value is true. The `LoadingDirective` is easy to use. The directive's selector is **`abpLoading`**. By adding the `abpLoading` attribute to an HTML element, you can activate the `LoadingDirective` for the HTML element when the value is true.
See an example usage: See an example usage:
@ -33,7 +34,7 @@ See an example usage:
cupiditate? Voluptas eaque voluptatum odio deleniti quo vel illum nemo accusamus nulla ratione cupiditate? Voluptas eaque voluptatum odio deleniti quo vel illum nemo accusamus nulla ratione
impedit dolorum expedita necessitatibus fugiat ullam beatae, optio eum cupiditate ducimus impedit dolorum expedita necessitatibus fugiat ullam beatae, optio eum cupiditate ducimus
architecto. architecto.
</div> </div>
``` ```

74
docs/en/framework/ui/angular/localization.md

@ -9,7 +9,7 @@ The Localization key format consists of 2 sections which are **Resource Name** a
```js ```js
const environment = { const environment = {
//... // ...
localization: { localization: {
defaultResourceName: "MyProjectName", defaultResourceName: "MyProjectName",
}, },
@ -49,7 +49,7 @@ Localization data is stored in key-value pairs:
```js ```js
{ {
//... // ...
AbpAccount: { // AbpAccount is the resource name AbpAccount: { // AbpAccount is the resource name
Key: "Value", Key: "Value",
PagerInfo: "Showing {0} to {1} of {2} entries" PagerInfo: "Showing {0} to {1} of {2} entries"
@ -121,12 +121,12 @@ See an example:
```ts ```ts
import { provideAbpCore, withOptions } from '@abp/ng.core'; import { provideAbpCore, withOptions } from '@abp/ng.core';
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
// ... // ...
provideAbpCore( provideAbpCore(
withOptions({ withOptions({
..., // ...,
localizations: [ localizations: [
{ {
culture: 'en', culture: 'en',
@ -155,22 +155,18 @@ import { provideAbpCore, withOptions } from '@abp/ng.core';
], ],
}), }),
), ),
...
], ],
}) };
export class AppModule {}
``` ```
...or, you can determine the localizations in a feature module: ...or, you can determine the localizations in a feature provider configuration:
```ts ```ts
// your feature module // your feature configuration
@NgModule({ export function provideFeatureConfiguration(): EnvironmentProviders{
imports: [ return provideAbpCoreChild({
//...other imports localizations: [
CoreModule.forChild({
localizations: [
{ {
culture: 'en', culture: 'en',
resources: [ resources: [
@ -196,9 +192,8 @@ export class AppModule {}
], ],
}, },
], ],
}), })
] }
})
``` ```
The localizations above can be used like this: The localizations above can be used like this:
@ -267,8 +262,8 @@ import { Component } from "@angular/core";
@Component({ @Component({
selector: "app-root", selector: "app-root",
template: ` template: `
<abp-loader-bar></abp-loader-bar> <abp-loader-bar />
<router-outlet></router-outlet> <router-outlet />
`, `,
}) })
export class AppComponent {} export class AppComponent {}
@ -276,7 +271,7 @@ export class AppComponent {}
## Registering a New Locale ## Registering a New Locale
Since ABP has more than one language, Angular locale files loads lazily using [Webpack's import function](https://webpack.js.org/api/module-methods/#import-1) to avoid increasing the bundle size and register to Angular core using the [`registerLocaleData`](https://angular.io/api/common/registerLocaleData) function. The chunks to be included in the bundle are specified by the [Webpack's magic comments](https://webpack.js.org/api/module-methods/#magic-comments) as hard-coded. Therefore a `registerLocale` function that returns Webpack `import` function must be passed to `CoreModule`. Since ABP has more than one language, Angular locale files loads lazily using [Webpack's import function](https://webpack.js.org/api/module-methods/#import-1) to avoid increasing the bundle size and register to Angular core using the [`registerLocaleData`](https://angular.io/api/common/registerLocaleData) function. The chunks to be included in the bundle are specified by the [Webpack's magic comments](https://webpack.js.org/api/module-methods/#magic-comments) as hard-coded. Therefore a `registerLocale` function that returns Webpack `import` function must be passed to `provideAbpCore(withOptions({...}))`.
### registerLocaleFn ### registerLocaleFn
@ -286,11 +281,12 @@ Since ABP has more than one language, Angular locale files loads lazily using [W
import { provideAbpCore, withOptions } from '@abp/ng.core'; import { provideAbpCore, withOptions } from '@abp/ng.core';
import { registerLocale } from '@abp/ng.core/locale'; import { registerLocale } from '@abp/ng.core/locale';
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
// ...
provideAbpCore( provideAbpCore(
withOptions({ withOptions({
..., // ...,
registerLocaleFn: registerLocale( registerLocaleFn: registerLocale(
// you can pass the cultureNameLocaleFileMap and errorHandlerFn as optionally // you can pass the cultureNameLocaleFileMap and errorHandlerFn as optionally
{ {
@ -302,10 +298,9 @@ import { registerLocale } from '@abp/ng.core/locale';
), ),
}), }),
), ),
... // ...
], ],
}) };
export class AppModule {}
``` ```
### Mapping of Culture Name to Angular Locale File Name ### Mapping of Culture Name to Angular Locale File Name
@ -317,19 +312,18 @@ Some of the culture names defined in .NET do not match Angular locales. In such
If you see an error like this, you should pass the `cultureNameLocaleFileMap` property like below to the `registerLocale` function. If you see an error like this, you should pass the `cultureNameLocaleFileMap` property like below to the `registerLocale` function.
```js ```js
// app.module.ts // app.config.ts
import { registerLocale } from '@abp/ng.core/locale'; import { registerLocale } from '@abp/ng.core/locale';
// if you have commercial license and the language management module, add the below import // if you have commercial license and the language management module, add the below import
// import { registerLocale } from '@volo/abp.ng.language-management/locale'; // import { registerLocale } from '@volo/abp.ng.language-management/locale';
export const appConfig: ApplicationConfig = {
@NgModule({
providers: [ providers: [
// ... // ...
provideAbpCore( provideAbpCore(
withOptions({ withOptions({
..., // ...,
registerLocaleFn: registerLocale( registerLocaleFn: registerLocale(
{ {
cultureNameLocaleFileMap: { cultureNameLocaleFileMap: {
@ -340,18 +334,18 @@ import { registerLocale } from '@abp/ng.core/locale';
) )
}), }),
), ),
] ],
}) };
``` ```
See [all locale files in Angular](https://github.com/angular/angular/tree/master/packages/common/locales). See [all locale files in Angular](https://github.com/angular/angular/tree/master/packages/common/locales).
### Adding a New Culture ### Adding a New Culture
Add the below code to the `app.module.ts` by replacing `your-locale` placeholder with a correct locale name. Add the below code to the `app.config.ts` by replacing `your-locale` placeholder with a correct locale name.
```js ```js
//app.module.ts //app.config.ts
import { storeLocaleData } from "@abp/ng.core/locale"; import { storeLocaleData } from "@abp/ng.core/locale";
import( import(
@ -361,7 +355,7 @@ import(
).then((m) => storeLocaleData(m.default, "your-locale")); ).then((m) => storeLocaleData(m.default, "your-locale"));
``` ```
...or a custom `registerLocale` function can be passed to the `CoreModule`: ...or a custom `registerLocale` function can be passed to the abp core provider configuration options:
```js ```js
// register-locale.ts // register-locale.ts
@ -376,22 +370,22 @@ export function registerLocale(locale: string) {
) )
} }
// app.module.ts // app.config.ts
import { registerLocale } from './register-locale'; import { registerLocale } from './register-locale';
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
// ... // ...
provideAbpCore( provideAbpCore(
withOptions({ withOptions({
..., // ...,
registerLocaleFn: registerLocale, registerLocaleFn: registerLocale,
}), }),
), ),
//... //...
] ],
}) };
``` ```
After this custom `registerLocale` function, since the en and fr added to the `webpackInclude`, only en and fr locale files will be created as chunks: After this custom `registerLocale` function, since the en and fr added to the `webpackInclude`, only en and fr locale files will be created as chunks:

25
docs/en/framework/ui/angular/lookup-components.md

@ -4,22 +4,7 @@ The Angular UI of ABP Commercial introduces some components with `abp-lookup-...
## Setup ## Setup
The components are in the _@volo/abp.commercial.ng.ui_ package, which is included in the ABP templates. So, as long as your project is a product of these templates and unless you delete the package, you have access to the lookup components. Here is how you import them in your Angular module: The components are in the _@volo/abp.commercial.ng.ui_ package, which is included in the ABP templates. So, as long as your project is a product of these templates and unless you delete the package, you have access to the lookup components. You can import these in your standalone components in order to be able to use them.
```javascript
import { CommercialUiModule } from '@volo/abp.commercial.ng.ui';
@NgModule({
imports: [
// other imports
CommercialUiModule,
],
// rest of the module metadata
})
export class YourModule {}
```
Now you can use the lookup components in your components declared by this module.
## Lookup HTTP Requests ## Lookup HTTP Requests
@ -48,7 +33,7 @@ Typeahead is a good choice when you have an unknown number of records for the re
![ABP Angular UI Typeahead Lookup](./images/angular-lookup-typeahead.gif) ![ABP Angular UI Typeahead Lookup](./images/angular-lookup-typeahead.gif)
Here is how it is used in the template. Do not forget to import `LookupTypeaheadComponent` in your component, and here is how it is used in the template.
```html ```html
<abp-lookup-typeahead <abp-lookup-typeahead
@ -57,7 +42,7 @@ Here is how it is used in the template.
displayNameProp="name" displayNameProp="name"
[editingData]="selected?.country" [editingData]="selected?.country"
[getFn]="service.getCountryLookup" [getFn]="service.getCountryLookup"
></abp-lookup-typeahead> />
``` ```
The available properties are as follows: The available properties are as follows:
@ -77,7 +62,7 @@ Select is a good choice when you have a low (and usually fixed) number of record
![ABP Angular UI Select Lookup](./images/angular-lookup-select.gif) ![ABP Angular UI Select Lookup](./images/angular-lookup-select.gif)
Here is how it is used in the template. Do not forget to import `LookupSelectComponent` in your component, and here is how it is used in the template.
```html ```html
<abp-lookup-select <abp-lookup-select
@ -85,7 +70,7 @@ Here is how it is used in the template.
formControlName="countryId" formControlName="countryId"
displayNameProp="name" displayNameProp="name"
[getFn]="service.getCountryLookup" [getFn]="service.getCountryLookup"
></abp-lookup-select> />
``` ```
The available properties are as follows: The available properties are as follows:

57
docs/en/framework/ui/angular/manage-profile-page-tabs.md

@ -9,7 +9,7 @@ See the example below, covers all features:
```ts ```ts
// manage-profile-tabs.provider.ts // manage-profile-tabs.provider.ts
import { APP_INITIALIZER, Component } from "@angular/core"; import { provideAppInitializer, Component } from "@angular/core";
import { TwoFactorTabComponent } from "@volo/abp.ng.account/public"; import { TwoFactorTabComponent } from "@volo/abp.ng.account/public";
import { import {
eAccountManageProfileTabNames, eAccountManageProfileTabNames,
@ -18,48 +18,47 @@ import {
import { MyAwesomeTabComponent } from "./my-awesome-tab/my-awesome-tab.component"; import { MyAwesomeTabComponent } from "./my-awesome-tab/my-awesome-tab.component";
@Component({ @Component({
standalone: true,
selector: "abp-my-awesome-tab", selector: "abp-my-awesome-tab",
template: `My Awesome Tab`, template: `My Awesome Tab`,
}) })
class MyAwesomeTabComponent {} class MyAwesomeTabComponent {}
export const MANAGE_PROFILE_TAB_PROVIDER = { export const MANAGE_PROFILE_TAB_PROVIDER = {
provide: APP_INITIALIZER, provideAppInitializer(()=>{
useFactory: configureManageProfileTabs, configureManageProfileTabs();
deps: [ManageProfileTabsService], }),
multi: true,
}; };
export function configureManageProfileTabs(tabs: ManageProfileTabsService) { export function configureManageProfileTabs() {
return () => { tabs = inject(ManageProfileTabsService);
tabs.add([ tabs.add([
{ {
name: "::MyAwesomeTab", // supports localization keys name: "::MyAwesomeTab", // supports localization keys
order: 5, order: 5,
component: MyAwesomeTabComponent, component: MyAwesomeTabComponent,
}, },
]); ]);
tabs.patch(eAccountManageProfileTabNames.TwoFactor, { tabs.patch(eAccountManageProfileTabNames.TwoFactor, {
name: "Two factor authentication", name: "Two factor authentication",
component: TwoFactorTabComponent, component: TwoFactorTabComponent,
}); });
tabs.remove([eAccountManageProfileTabNames.ProfilePicture]); tabs.remove([eAccountManageProfileTabNames.ProfilePicture]);
};
} }
``` ```
```ts ```ts
//app.module.ts //app.config.ts
import { MANAGE_PROFILE_TAB_PROVIDER } from "./manage-profile-tabs.provider"; import { MANAGE_PROFILE_TAB_PROVIDER } from "./manage-profile-tabs.provider";
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [MANAGE_PROFILE_TAB_PROVIDER], providers: [
}) // ...
export class AppModule {} MANAGE_PROFILE_TAB_PROVIDER
],
};
``` ```
What we have done above; What we have done above;
@ -70,7 +69,7 @@ What we have done above;
- Renamed the "Two factor" tab label. - Renamed the "Two factor" tab label.
- Removed the "Profile picture" tab. - Removed the "Profile picture" tab.
- Determined the `MANAGE_PROFILE_TAB_PROVIDER` to be able to run the `configureManageProfileTabs` function on initialization. - Determined the `MANAGE_PROFILE_TAB_PROVIDER` to be able to run the `configureManageProfileTabs` function on initialization.
- Registered the `MANAGE_PROFILE_TAB_PROVIDER` to the `AppModule` providers. - Registered the `MANAGE_PROFILE_TAB_PROVIDER` to the `appConfig` providers.
See the result: See the result:

69
docs/en/framework/ui/angular/modal.md

@ -15,27 +15,33 @@ The `abp-modal` provides some additional benefits:
## Getting Started ## Getting Started
In order to use the `abp-modal` in an HTML template, the **`ThemeSharedModule`** should be imported into your module like this: In order to use the `abp-modal` in an HTML template, the **`ModalComponent`** should be imported into your component like this:
```js ```js
// sample.component.ts
// ... // ...
import { ThemeSharedModule } from '@abp/ng.theme.shared'; import { ModalComponent, ModalCloseDirective } from '@abp/ng.theme.shared';
@NgModule({ @Component({
//... //...
imports: [..., ThemeSharedModule], ,
imports: [
// ...,
ModalComponent,
ModalCloseDirective // if you use `abpClose` directive in the html template
],
}) })
export class MyFeatureModule {} export class SampleComponent {
isModalOpen = false;
}
``` ```
## Usage
You can add the `abp-modal` to your component very quickly. See an example:
```html ```html
<!-- sample.component.html --> <!-- sample.component.html -->
<button class="btn btn-primary" (click)="isModalOpen = true">Open modal</button> <button class="btn btn-primary" (click)="isModalOpen = true">
Open modal
</button>
<abp-modal [(visible)]="isModalOpen"> <abp-modal [(visible)]="isModalOpen">
<ng-template #abpHeader> <ng-template #abpHeader>
@ -43,24 +49,17 @@ You can add the `abp-modal` to your component very quickly. See an example:
</ng-template> </ng-template>
<ng-template #abpBody> <ng-template #abpBody>
<p>Modal content</p> <p>Modal content</p>
</ng-template> </ng-template>
<ng-template #abpFooter> <ng-template #abpFooter>
<button type="button" class="btn btn-secondary" abpClose>Close</button> <button type="button" class="btn btn-secondary" abpClose>
Close
</button>
</ng-template> </ng-template>
</abp-modal> </abp-modal>
``` ```
```js
// sample.component.ts
@Component(/* component metadata */)
export class SampleComponent {
isModalOpen = false
}
```
![Example modal result](./images/modal-result-1.jpg) ![Example modal result](./images/modal-result-1.jpg)
@ -136,7 +135,10 @@ import { FormBuilder, Validators } from '@angular/forms';
@Component(/* component metadata */) @Component(/* component metadata */)
export class BookComponent { export class BookComponent {
form = this.fb.group({ private fb = inject(FormBuilder);
private service = inject(BookService);
form = this.fb.group({
author: [null, [Validators.required]], author: [null, [Validators.required]],
name: [null, [Validators.required]], name: [null, [Validators.required]],
price: [null, [Validators.required, Validators.min(0)]], price: [null, [Validators.required, Validators.min(0)]],
@ -148,10 +150,10 @@ export class BookComponent {
isModalOpen: boolean; isModalOpen: boolean;
constructor(private fb: FormBuilder, private service: BookService) {}
save() { save() {
if (this.form.invalid) return; if (this.form.invalid) {
return;
}
this.inProgress = true; this.inProgress = true;
@ -257,19 +259,16 @@ export class NgbdModalOptions {
**`suppressUnsavedChangesWarning`** is a boolean input that determines whether the confirmation popup triggering active or not. It can also be set globally as shown below: **`suppressUnsavedChangesWarning`** is a boolean input that determines whether the confirmation popup triggering active or not. It can also be set globally as shown below:
```ts ```ts
//app.module.ts // app.config.ts
// app.module.ts
import { SUPPRESS_UNSAVED_CHANGES_WARNING } from '@abp/ng.theme.shared'; import { SUPPRESS_UNSAVED_CHANGES_WARNING } from '@abp/ng.theme.shared';
// ... export const appConfig: ApplicationConfig = {
providers: [
@NgModule({ // ...
// ... { provide: SUPPRESS_UNSAVED_CHANGES_WARNING, useValue: true }
providers: [{provide: SUPPRESS_UNSAVED_CHANGES_WARNING, useValue: true}] ],
}) };
export class AppModule {}
``` ```
Note: The `suppressUnsavedChangesWarning` input of `abp-modal` value overrides the `SUPPRESS_UNSAVED_CHANGES_WARNING` injection token value. Note: The `suppressUnsavedChangesWarning` input of `abp-modal` value overrides the `SUPPRESS_UNSAVED_CHANGES_WARNING` injection token value.

90
docs/en/framework/ui/angular/modifying-the-menu.md

@ -59,32 +59,33 @@ An alternative and probably cleaner way is to use a route provider. First create
```js ```js
// route.provider.ts // route.provider.ts
import { RoutesService, eLayoutType } from '@abp/ng.core'; import { RoutesService, eLayoutType } from '@abp/ng.core';
import { APP_INITIALIZER } from '@angular/core'; import { provideAppInitializer } from '@angular/core';
export const APP_ROUTE_PROVIDER = [ export const APP_ROUTE_PROVIDER = [
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true }, provideAppInitializer(() => {
configureRoutes();
}),
]; ];
function configureRoutes(routes: RoutesService) { function configureRoutes() {
return () => { const routesService = inject(RoutesService);
routes.add([ routes.add([
{ {
path: '/your-path', path: '/your-path',
name: 'Your navigation', name: 'Your navigation',
requiredPolicy: 'permission key here', requiredPolicy: 'permission key here',
order: 101, order: 101,
iconClass: 'fas fa-question-circle', iconClass: 'fas fa-question-circle',
layout: eLayoutType.application, layout: eLayoutType.application,
}, },
{ {
path: '/your-path/child', path: '/your-path/child',
name: 'Your child navigation', name: 'Your child navigation',
parentName: 'Your navigation', parentName: 'Your navigation',
requiredPolicy: 'permission key here', requiredPolicy: 'permission key here',
order: 1, order: 1,
}, },
]); ]);
};
} }
``` ```
@ -95,22 +96,21 @@ We can also define a group for navigation elements. It's an optional property
// route.provider.ts // route.provider.ts
import { RoutesService } from '@abp/ng.core'; import { RoutesService } from '@abp/ng.core';
function configureRoutes(routes: RoutesService) { function configureRoutes() {
return () => { const routesService = inject(RoutesService);
routes.add([ routes.add([
{ {
//etc.. //etc..
group: 'ModuleName::GroupName' group: 'ModuleName::GroupName'
}, },
{ {
path: '/your-path/child', path: '/your-path/child',
name: 'Your child navigation', name: 'Your child navigation',
parentName: 'Your navigation', parentName: 'Your navigation',
requiredPolicy: 'permission key here', requiredPolicy: 'permission key here',
order: 1, order: 1,
}, },
]); ]);
};
} }
``` ```
@ -131,25 +131,23 @@ export class AppComponent {
} }
``` ```
...and then in app.module.ts... ...and then in app.config.ts...
- The `groupedVisible` method will return the `Others` group for ungrouped items, the default key is `AbpUi::OthersGroup`, we can change this `key` via the `OTHERS_GROUP` injection token - The `groupedVisible` method will return the `Others` group for ungrouped items, the default key is `AbpUi::OthersGroup`, we can change this `key` via the `OTHERS_GROUP` injection token
```js ```js
import { NgModule } from '@angular/core';
import { OTHERS_GROUP } from '@abp/ng.core'; import { OTHERS_GROUP } from '@abp/ng.core';
import { APP_ROUTE_PROVIDER } from './route.provider'; import { APP_ROUTE_PROVIDER } from './route.provider';
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
// ...
APP_ROUTE_PROVIDER, APP_ROUTE_PROVIDER,
{ {
provide: OTHERS_GROUP, provide: OTHERS_GROUP,
useValue: 'ModuleName::MyOthersGroupKey', useValue: 'ModuleName::MyOthersGroupKey',
}, },
], ],
// imports, declarations, and bootstrap };
})
export class AppModule {}
``` ```
### Singularize Route Item ### Singularize Route Item
@ -182,9 +180,9 @@ Here is what every property works as:
- `invisible` makes the item invisible in the menu. (default: `false`) - `invisible` makes the item invisible in the menu. (default: `false`)
- `group` is an optional property that is used to group together related routes in an application. (type: `string`, default: `AbpUi::OthersGroup`) - `group` is an optional property that is used to group together related routes in an application. (type: `string`, default: `AbpUi::OthersGroup`)
### Via `routes` Property in `AppRoutingModule` ### Via `routes` Property in `APP_ROUTES`
You can define your routes by adding `routes` as a child property to `data` property of a route configuration in the `app-routing.module`. The `@abp/ng.core` package organizes your routes and stores them in the `RoutesService`. You can define your routes by adding `routes` as a child property to `data` property of a route configuration in the `app.routes.ts`. The `@abp/ng.core` package organizes your routes and stores them in the `RoutesService`.
You can add the `routes` property like below: You can add the `routes` property like below:

13
docs/en/framework/ui/angular/multi-tenancy.md

@ -133,12 +133,9 @@ Example:
```ts ```ts
import { TENANT_NOT_FOUND_BY_NAME } from '@abp/ng.core'; import { TENANT_NOT_FOUND_BY_NAME } from '@abp/ng.core';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [
// removed for clarity
],
providers: [ providers: [
// removed for clarity // removed for clarity
{ {
provide: TENANT_NOT_FOUND_BY_NAME, provide: TENANT_NOT_FOUND_BY_NAME,
useFactory: function () { useFactory: function () {
@ -148,11 +145,7 @@ import { TENANT_NOT_FOUND_BY_NAME } from '@abp/ng.core';
}, },
}, },
], ],
declarations: [AppComponent], };
bootstrap: [AppComponent],
})
export class AppModule {}
``` ```
## See Also ## See Also

3
docs/en/framework/ui/angular/oauth-module.md

@ -2,8 +2,7 @@
The authentication functionality has been moved from @abp/ng.core to @abp/ng.ouath since v7.0. The authentication functionality has been moved from @abp/ng.core to @abp/ng.ouath since v7.0.
If your app is version 8.3 or higher, you should include "provideAbpOAuth()" in your app.module.ts as an providers after "provideAbpCore() If your app is version 8.3 or higher, you should include "provideAbpOAuth()" after "provideAbpCore()" in the `appConfig` array of your `app.config.ts`.
".
Those abstractions can be found in the @abp/ng-core packages. Those abstractions can be found in the @abp/ng-core packages.

84
docs/en/framework/ui/angular/page-component.md

@ -14,10 +14,10 @@ Let's look at the following example without `abp-page` component.
<h1 class="content-header-title">{%{{{ '::Dashboard' | abpLocalization }}}%}</h1> <h1 class="content-header-title">{%{{{ '::Dashboard' | abpLocalization }}}%}</h1>
</div> </div>
<div id="breadcrumb" class="col-lg-auto pl-lg-0"> <div id="breadcrumb" class="col-lg-auto pl-lg-0">
<abp-breadcrumb></abp-breadcrumb> <abp-breadcrumb />
</div> </div>
<div class="col"> <div class="col">
<abp-page-toolbar [record]="data"></abp-page-toolbar> <abp-page-toolbar [record]="data" />
</div> </div>
</div> </div>
@ -42,22 +42,19 @@ export enum PageParts {
## Usage ## Usage
Firstly, you need to import `PageModule` from `@abp/ng.components/page` as follows: Firstly, you need to import Page components from `@abp/ng.components/page` based on your usage. Here is an example:
`dashboard.module.ts` `dashboard.component.ts`
```javascript ```javascript
import { PageModule } from '@abp/ng.components/page';
import { DashboardComponent } from './dashboard.component';
@NgModule({ @Component({
declarations: [DashboardComponent], imports: [ PageComponent, ... ]
imports: [PageModule]
}) })
export class DashboardModule {} export class  DashboardComponent {}
``` ```
And change the template of `dashboard.component.ts` to the following: And change the template of `dashboard.component.html` to the following:
```html ```html
<abp-page [title]="'::Dashboard' | abpLocalization" [toolbar]="data"> <abp-page [title]="'::Dashboard' | abpLocalization" [toolbar]="data">
@ -75,35 +72,55 @@ And change the template of `dashboard.component.ts` to the following:
## Overriding template ## Overriding template
If you need to replace the template of any part, you can use the following sub-components. If you need to replace the template of any part, you can use the following sub-components. You will need to import these components and modify the html template accordingly.
```html ```javascript
<abp-page> import {
<abp-page-title-container class="col"> PageComponent,
<h2>Custom Title</h2> PageTitleContainerComponent,
</abp-page-title-container> PageBreadcrumbContainerComponent,
PageToolbarContainerComponent
<abp-page-breacrumb-container class="col"> } from '@abp/ng.components/page';
<my-breadcrumb></my-breadcrumb>
</abp-page-breacrumb-container> @Component({
selector: 'app-sample-component',
<abp-page-toolbar-container class="col"> template: `
<button (click)="doSth()">Some Action</button> <abp-page>
</abp-page-toolbar-container> <abp-page-title-container class="col">
</abp-page> <h2>Custom Title</h2>
</abp-page-title-container>
<abp-page-breacrumb-container class="col">
<my-breadcrumb />
</abp-page-breacrumb-container>
<abp-page-toolbar-container class="col">
<button (click)="doSth()">Some Action</button>
</abp-page-toolbar-container>
</abp-page>
`
imports: [
PageComponent,
PageTitleContainerComponent,
PageBreadcrumbContainerComponent,
MyBreadcrumbComponent,
PageToolbarContainerComponent
]
})
export class SampleCompnent {}
``` ```
You do not have to provide them all. You can just use which one you need to replace. These components have priority over the inputs declared above. If you use these components, you can omit the inputs. You do not have to provide them all. You can just use which one you need to replace. These components have priority over the inputs declared above. If you use these components, you can omit the inputs.
## PagePartDirective ## PagePartDirective
`PageModule` provides a structural directive that is used internally within `PageComponent` and can also be used externally. `Components` package provides a structural directive that is used internally within `PageComponent` and can also be used externally.
`PageComponent` employs this directive internally as follows: `PageComponent` employs this directive internally as follows:
```html ```html
<div class="col-lg-auto pl-lg-0" *abpPagePart="pageParts.breadcrumb"> <div class="col-lg-auto pl-lg-0" *abpPagePart="pageParts.breadcrumb">
<abp-breadcrumb></abp-breadcrumb> <abp-breadcrumb />
</div> </div>
``` ```
@ -111,7 +128,7 @@ It also can take a context input as follows:
```html ```html
<div class="col" *abpPagePart="pageParts.toolbar; context: toolbarData"> <div class="col" *abpPagePart="pageParts.toolbar; context: toolbarData">
<abp-page-toolbar [record]="toolbarData"></abp-page-toolbar> <abp-page-toolbar [record]="toolbarData" />
</div> </div>
``` ```
@ -194,17 +211,14 @@ export class MyPageRenderStrategy implements PageRenderStrategy {
}) })
export class DashboardComponent {} export class DashboardComponent {}
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [PageModule],
declarations: [DashboardComponent],
providers: [ providers: [
{ {
provide: PAGE_RENDER_STRATEGY, provide: PAGE_RENDER_STRATEGY,
useClass: MyPageRenderStrategy, useClass: MyPageRenderStrategy,
} }
] ],
}) };
export class DashboardModule {}
``` ```
## See Also ## See Also

32
docs/en/framework/ui/angular/page-toolbar-extensions.md

@ -14,7 +14,7 @@ In this example, we will add a "Click Me!" action and log `userName` of all user
### Step 1. Create Toolbar Action Contributors ### Step 1. Create Toolbar Action Contributors
The following code prepares a constant named `identityToolbarActionContributors`, ready to be imported and used in your root module: The following code prepares a constant named `identityToolbarActionContributors`, ready to be imported and used in your root application configuration:
```js ```js
// src/app/toolbar-action-contributors.ts // src/app/toolbar-action-contributors.ts
@ -53,22 +53,22 @@ The list of actions, conveniently named as `actionList`, is a **doubly linked li
### Step 2. Import and Use Toolbar Action Contributors ### Step 2. Import and Use Toolbar Action Contributors
Import `identityToolbarActionContributors` in your routing module and pass it to the static `forLazy` method of `IdentityModule` as seen below: Import `identityToolbarActionContributors` in your routing configuration and pass it to the static `createRoutes` method for `identity` route as seen below:
```js ```js
// src/app/app-routing.module.ts // src/app/app.routes.ts
// other imports // other imports
import { identityToolbarActionContributors } from './toolbar-action-contributors'; import { identityToolbarActionContributors } from './toolbar-action-contributors';
const routes: Routes = [ export const APP_ROUTES: Routes = [
// other routes // other routes
{ {
path: 'identity', path: 'identity',
loadChildren: () => loadChildren: () =>
import('@abp/ng.identity').then(m => import('@abp/ng.identity').then(c =>
m.IdentityModule.forLazy({ c.createRoutes({
toolbarActionContributors: identityToolbarActionContributors, toolbarActionContributors: identityToolbarActionContributors,
}) })
), ),
@ -78,7 +78,7 @@ const routes: Routes = [
]; ];
``` ```
That is it, `logUserNames` toolbar action will be added as the first action on the page toolbar in the users page (`UsersComponent`) of the `IdentityModule`. That is it, `logUserNames` toolbar action will be added as the first action on the page toolbar in the users page (`UsersComponent`) of the `identity` package.
## How to Add a Custom Component to Page Toolbar ## How to Add a Custom Component to Page Toolbar
@ -93,9 +93,9 @@ We need to have a component before we can pass it to the toolbar action contribu
```js ```js
// src/app/click-me-button.component.ts // src/app/click-me-button.component.ts
import { Component, Inject } from '@angular/core';
import { IdentityUserDto } from '@abp/ng.identity/proxy'; import { IdentityUserDto } from '@abp/ng.identity/proxy';
import { ActionData, EXTENSIONS_ACTION_DATA } from '@abp/ng.components/extensible'; import { ActionData, EXTENSIONS_ACTION_DATA } from '@abp/ng.components/extensible';
import { Component, Inject } from '@angular/core';
@Component({ @Component({
selector: 'app-click-me-button', selector: 'app-click-me-button',
@ -120,7 +120,7 @@ Here, `EXTENSIONS_ACTION_DATA` token provides us the context from the page toolb
### Step 2. Create Toolbar Action Contributors ### Step 2. Create Toolbar Action Contributors
The following code prepares a constant named `identityToolbarActionContributors`, ready to be imported and used in your root module. When `ToolbarComponent` is used instead of `ToolbarAction`, we can pass a component in: The following code prepares a constant named `identityToolbarActionContributors`, ready to be imported and used in your root application configuration. When `ToolbarComponent` is used instead of `ToolbarAction`, we can pass a component in:
```js ```js
// src/app/toolbar-action-contributors.ts // src/app/toolbar-action-contributors.ts
@ -156,22 +156,22 @@ The list of actions, conveniently named as `actionList`, is a **doubly linked li
### Step 3. Import and Use Toolbar Action Contributors ### Step 3. Import and Use Toolbar Action Contributors
Import `identityToolbarActionContributors` in your routing module and pass it to the static `forLazy` method of `IdentityModule` as seen below. Import `identityToolbarActionContributors` in your routing configuration and pass it to the static `createRoutes` method for `identity` route as seen below.
```js ```js
// src/app/app-routing.module.ts // src/app/app.routes.ts
// other imports // other imports
import { identityToolbarActionContributors } from './toolbar-action-contributors'; import { identityToolbarActionContributors } from './toolbar-action-contributors';
const routes: Routes = [ export const APP_ROUTES: Routes = [
// other routes // other routes
{ {
path: 'identity', path: 'identity',
loadChildren: () => loadChildren: () =>
import('@abp/ng.identity').then(m => import('@abp/ng.identity').then(c =>
m.IdentityModule.forLazy({ c.createRoutes({
toolbarActionContributors: identityToolbarActionContributors, toolbarActionContributors: identityToolbarActionContributors,
}) })
), ),
@ -181,7 +181,7 @@ const routes: Routes = [
]; ];
``` ```
That is it, `logUserNames` toolbar action will be added as the first action on the page toolbar in the users page (`UsersComponent`) of the `IdentityModule` and it will be triggered by a custom button, i.e. `ClickMeButtonComponent`. Please note that **component projection is not limited to buttons** and you may use other UI components. That is it, `logUserNames` toolbar action will be added as the first action on the page toolbar in the users page (`UsersComponent`) of the `identity` package and it will be triggered by a custom button, i.e. `ClickMeButtonComponent`. Please note that **component projection is not limited to buttons** and you may use other UI components.
## How to Place a Custom Modal and Trigger It by Toolbar Actions ## How to Place a Custom Modal and Trigger It by Toolbar Actions
@ -380,7 +380,7 @@ export const identityEntityActionContributors = {
### ToolbarActionContributorCallback\<R = any\> ### ToolbarActionContributorCallback\<R = any\>
`ToolbarActionContributorCallback` is the type that you can pass as toolbar action contributor callbacks to static `forLazy` methods of the modules. `ToolbarActionContributorCallback` is the type that you can pass as toolbar action contributor callbacks to static `createRoutes` methods of the packages.
```js ```js
// exportUsersContributor should have ToolbarActionContributorCallback<IdentityUserDto[]> type // exportUsersContributor should have ToolbarActionContributorCallback<IdentityUserDto[]> type

2
docs/en/framework/ui/angular/password-complexity-indicator-component.md

@ -42,7 +42,7 @@ The `PasswordComplexityIndicatorService` is for calculating the password complex
It's easy, imagine you have a password input that you want to add the complexity indicator under. Put this component under the input It's easy, imagine you have a password input that you want to add the complexity indicator under. Put this component under the input
```ts ```ts
<abp-password-complexity-indicator [progressBar]="ProgressBarStatsObject"></abp-password-complexity-indicator> <abp-password-complexity-indicator [progressBar]="ProgressBarStatsObject" />
``` ```
- Pass the password to the `validatePassword` method of the `PasswordComplexityIndicatorService`, and bind return the value to the `progressBar` property of the `abp-password-complexity-indicator` - Pass the password to the `validatePassword` method of the `PasswordComplexityIndicatorService`, and bind return the value to the `progressBar` property of the `abp-password-complexity-indicator`

9
docs/en/framework/ui/angular/permission-management.md

@ -100,11 +100,10 @@ export class CustomPermissionService extends PermissionService {
} }
``` ```
- Then, in `app.module.ts`, provide this service as follows: - Then, in `app.config.ts`, provide this service as follows:
```js ```js
@NgModule({ export const appConfig: ApplicationConfig = {
// ...
providers: [ providers: [
// ... // ...
{ {
@ -112,9 +111,7 @@ export class CustomPermissionService extends PermissionService {
useExisting: CustomPermissionService, useExisting: CustomPermissionService,
}, },
], ],
// ... };
})
export class AppModule {}
``` ```
That's it. Now, when a directive/guard asks for `PermissionService` from angular, it will inject your service. That's it. Now, when a directive/guard asks for `PermissionService` from angular, it will inject your service.

2
docs/en/framework/ui/angular/pwa-configuration.md

@ -38,7 +38,7 @@ So, Angular CLI updates some files and add a few others:
- `serviceWorker` is `true` in production build. - `serviceWorker` is `true` in production build.
- `ngswConfigPath` refers to _ngsw-config.json_. - `ngswConfigPath` refers to _ngsw-config.json_.
- **package.json** has _@angular/service-worker_ as a new dependency. - **package.json** has _@angular/service-worker_ as a new dependency.
- **app.module.ts** imports `ServiceWorkerModule` and registers a service worker filename. - **app.config.ts** imports `ServiceWorkerModule` and registers a service worker filename.
- **index.html** has following modifications: - **index.html** has following modifications:
- A `<link>` element that refers to _manifest.webmanifest_. - A `<link>` element that refers to _manifest.webmanifest_.
- A `<meta>` tag that sets a theme color. - A `<meta>` tag that sets a theme color.

21
docs/en/framework/ui/angular/quick-start.md

@ -54,28 +54,27 @@ Here is what these folders and files are for:
- **.vscode** has extension recommendations in it. - **.vscode** has extension recommendations in it.
- **e2e** is a separate app for possible end-to-end tests. - **e2e** is a separate app for possible end-to-end tests.
- **src** is where the source files for your application are placed. We will have a closer look in a minute. - **src** is where the source files for your application are placed. We will have a closer look in a minute.
- **.browserlistrc** helps [configuring browser compatibility of your Angular app](https://angular.io/guide/build#configuring-browser-compatibility). - **.browserlistrc** helps [configuring browser compatibility of your Angular app](https://angular.dev/tools/cli/build#configuring-browser-compatibility).
- **.editorconfig** helps you have a shared coding style for separate editors and IDEs. Check [EditorConfig.org](https://editorconfig.org/) for details. - **.editorconfig** helps you have a shared coding style for separate editors and IDEs. Check [EditorConfig.org](https://editorconfig.org/) for details.
- **.gitignore** defined which files and folders should not be tracked by git. Check [git documentation](https://git-scm.com/docs/gitignore) for details. - **.gitignore** defined which files and folders should not be tracked by git. Check [git documentation](https://git-scm.com/docs/gitignore) for details.
- **.prettierrc** includes simple coding style choices for [Prettier](https://prettier.io/), an auto-formatter for TypeScript, HTML, CSS, and more. If you install recommended extensions to VS Code, you will never have to format your code anymore. - **.prettierrc** includes simple coding style choices for [Prettier](https://prettier.io/), an auto-formatter for TypeScript, HTML, CSS, and more. If you install recommended extensions to VS Code, you will never have to format your code anymore.
- **angular.json** is where Angular workspace is defined. It holds project configurations and workspace preferences. Please refer to [Angular workspace configuration](https://angular.io/guide/workspace-config) for details. - **angular.json** is where Angular workspace is defined. It holds project configurations and workspace preferences. Please refer to [Angular workspace configuration](https://angular.dev/reference/configs/workspace-config) for details.
- **karma.conf.js** holds [Karma test runner](https://karma-runner.github.io/) configurations. - **karma.conf.js** holds [Karma test runner](https://karma-runner.github.io/) configurations.
- **package.json** is where your [package dependencies](https://angular.io/guide/npm-packages) are listed. It also includes some useful scripts for developing, testing, and building your application. - **package.json** is where your [package dependencies](https://angular.dev/reference/configs/npm-packages) are listed. It also includes some useful scripts for developing, testing, and building your application.
- **README.md** includes some of Angular CLI command examples. You either have to install Angular CLI globally or run these commands starting with `yarn` or `npx` to make them work. - **README.md** includes some of Angular CLI command examples. You either have to install Angular CLI globally or run these commands starting with `yarn` or `npx` to make them work.
- **start.ps1** is a simple PowerShell script to install dependencies and start a [development server via Angular CLI](https://angular.io/cli/serve), but you probably will not need that after reading this document. - **start.ps1** is a simple PowerShell script to install dependencies and start a [development server via Angular CLI](https://angular.dev/cli/serve), but you probably will not need that after reading this document.
- **tsconfig.json** and all other [tsconfig files](https://angular.io/guide/typescript-configuration) in general, include some TypeScript and Angular compile options. - **tsconfig.json** and all other [tsconfig files](https://angular.dev/reference/configs/angular-compiler-options) in general, include some TypeScript and Angular compile options.
- **yarn.lock** enables installing consistent package versions across different devices so that working application build will not break because of a package update. Please read [Yarn documentation](https://classic.yarnpkg.com/en/docs/yarn-lock/) if you are interested in more information on the topic. If you have decided to use npm, please remove this file and keep the [package-lock.json](https://docs.npmjs.com/files/package-lock.json) instead. - **yarn.lock** enables installing consistent package versions across different devices so that working application build will not break because of a package update. Please read [Yarn documentation](https://classic.yarnpkg.com/en/docs/yarn-lock/) if you are interested in more information on the topic. If you have decided to use npm, please remove this file and keep the [package-lock.json](https://docs.npmjs.com/files/package-lock.json) instead.
Now let us take a look at the contents of the source folder. Now let us take a look at the contents of the source folder.
<img alt="Angular project source folder structure" src="./images/quick-start---source-folder-structure.png" width="300px" style="max-width:100%"> <img alt="Angular project source folder structure" src="./images/quick-start---source-folder-structure.png" width="300px" style="max-width:100%">
- **app** is the main directory you put your application files in. Any module, component, directive, service, pipe, guard, interceptor, etc. should be placed here. You are free to choose any folder structure, but [organizing Angular applications based on modules](https://angular.io/guide/module-types) is generally a fine practice. - **app** is the main directory you put your application files in. Any component, directive, service, pipe, guard, interceptor, etc. should be placed here. You are free to choose any folder structure, but [organizing Angular applications using configuration-based structure](https://angular.dev/reference/configs/file-structure) is generally a fine practice, especially when using standalone APIs. This replaces the older convention of organizing strictly by NgModules.
- **home** is a predefined module and acts as a welcome page. It also demonstrates how a feature-based folder structure may look like. More complex features will probably have sub-features, thus inner folders. You may change the home folder however you like. - **home** is a predefined component and acts as a welcome page. It also demonstrates how a feature-based folder structure may look like. More complex features will probably have sub-features, thus inner folders. You may change the home folder however you like.
- **shared** is spared for reusable code that works for several modules. Some, including yours truly, may disagree with using a single module for all shared code, so consider adding standalone sub-modules inside this folder instead of adding everything into **shared.module.ts**. - **app.routes.ts** is where your top-level routes are defined. Angular is capable of [lazy loading routes now](https://angular.dev/reference/migrations/route-lazy-loading), so not all routes will be here. You may think of Angular routing as a tree and this file is the top of the tree.
- **app-routing.module.ts** is where your top-level routes are defined. Angular is capable of [lazy loading feature modules](https://angular.io/guide/lazy-loading-ngmodules), so not all routes will be here. You may think of Angular routing as a tree and this file is the top of the tree.
- **app.component.ts** is essentially the top component that holds the dynamic application layout. - **app.component.ts** is essentially the top component that holds the dynamic application layout.
- **app.module.ts** is the [root module](https://angular.io/guide/bootstrapping) that includes information about how parts of your application are related and what to run at the initiation of your application. - **app.config.ts** is the [root configuration](https://angular.dev/api/platform-browser/bootstrapApplication) that includes information about how parts of your application are related and what to run at the initiation of your application.
- **route.provider.ts** is used for [modifying the menu](../angular/modifying-the-menu.md). - **route.provider.ts** is used for [modifying the menu](../angular/modifying-the-menu.md).
- **assets** is for static files. A file (e.g. an image) placed in this folder will be available as is when the application is served. - **assets** is for static files. A file (e.g. an image) placed in this folder will be available as is when the application is served.
- **environments** includes one file per environment configuration. There are two configurations by default, but you may always introduce another one. These files are directly referred to in _angular.json_ and help you have different builds and application variables. Please refer to [configuring Angular application environments](https://angular.io/guide/build#configuring-application-environments) for details. - **environments** includes one file per environment configuration. There are two configurations by default, but you may always introduce another one. These files are directly referred to in _angular.json_ and help you have different builds and application variables. Please refer to [configuring Angular application environments](https://angular.io/guide/build#configuring-application-environments) for details.
@ -155,7 +154,7 @@ export const environment = {
} as Config.Environment; } as Config.Environment;
``` ```
When you run the development server, variables defined in _environment.ts_ take effect. Similarly, in production mode, the default environment is replaced by _environment.prod.ts_ and completely different variables become effective. You may even [create a new build configuration](https://angular.io/guide/workspace-config#build-configs) and set [file replacements](https://angular.io/guide/build#configure-target-specific-file-replacements) to use a completely new environment. For now, we will start a production build: When you run the development server, variables defined in _environment.ts_ take effect. Similarly, in production mode, the default environment is replaced by _environment.prod.ts_ and completely different variables become effective. You may even [create a new build configuration](https://angular.dev/reference/configs/workspace-config#alternate-build-configurations) and set [file replacements](https://angular.io/guide/build#configure-target-specific-file-replacements) to use a completely new environment. For now, we will start a production build:
1. Open your terminal and navigate to the root Angular folder. 1. Open your terminal and navigate to the root Angular folder.
2. Run `yarn` or `npm install` if you have not installed dependencies already. 2. Run `yarn` or `npm install` if you have not installed dependencies already.

36
docs/en/framework/ui/angular/show-password-directive.md

@ -4,24 +4,20 @@ In password input, text can be shown easily via changing input type attribute to
## Getting Started ## Getting Started
`ShowPasswordDirective` is standalone. In order to use the `ShowPasswordDirective` in an HTML template, import it to related module or your standalone component: `ShowPasswordDirective` is standalone. In order to use the it in an HTML template, import it to your component:
**Importing to NgModule** **Importing to Component**
```ts ```ts
import { ShowPasswordDirective } from '@abp/ng.core'; import { ShowPasswordDirective } from '@abp/ng.core';
@NgModule({ @Component({
//... //...
declarations: [
...,
TestComponent
],
imports: [ imports: [
..., // ...,
ShowPasswordDirective ShowPasswordDirective
], ],
}) })
export class MyFeatureModule {} export class TestComponent {}
``` ```
## Usage ## Usage
@ -30,28 +26,10 @@ The `ShowPasswordDirective` is very easy to use. The directive's selector is **`
See an example usage: See an example usage:
**NgModule Component usage**
```ts
@Component({
selector: 'test-component',
template: `
<div class="d-flex flex-column">
<label>Password</label>
<input [abpShowPassword]="showPassword"/>
<i (click)="showPassword = !showPassword">icon</i>
</div>
`
})
export class TestComponent{
showPassword = false;
}
```
**Standalone Component usage**
```ts ```ts
import { ShowPasswordDirective } from '@abp/ng.core'; import { ShowPasswordDirective } from '@abp/ng.core';
@Component({ @Component({
selector: 'standalone-component', selector: 'sample-component',
standalone: true,
template: ` template: `
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<label>Password</label> <label>Password</label>
@ -61,7 +39,7 @@ import { ShowPasswordDirective } from '@abp/ng.core';
`, `,
imports: [ShowPasswordDirective] imports: [ShowPasswordDirective]
}) })
export class StandaloneComponent{ export class SampleComponent{
showPassword = false; showPassword = false;
} }
``` ```

11
docs/en/framework/ui/angular/sorting-navigation-elements.md

@ -19,19 +19,18 @@ This documentation describes how the navigation elements are sorted and how to c
# How to Customize # How to Customize
**`in app.module.ts`** **`in app.config.ts`**
```ts ```ts
import { SORT_COMPARE_FUNC } from "@abp/ng.core"; import { SORT_COMPARE_FUNC } from "@abp/ng.core";
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
...{ // ...
{
provide: SORT_COMPARE_FUNC, provide: SORT_COMPARE_FUNC,
useFactory: yourCompareFuncFactory, useFactory: yourCompareFuncFactory,
}, },
], ],
// imports, declarations, and bootstrap };
})
export class AppModule {}
``` ```

12
docs/en/framework/ui/angular/toaster-service.md

@ -4,7 +4,7 @@ You can use the `ToasterService` in @abp/ng.theme.shared package to display mess
## Getting Started ## Getting Started
You do not have to provide the `ToasterService` at module or component level, because it is already **provided in root**. You can inject and start using it immediately in your components, directives, or services. You do not have to provide the `ToasterService` at component level, because it is already **provided in root**. You can inject and start using it immediately in your components, directives, or services.
```js ```js
import { ToasterService } from '@abp/ng.theme.shared'; import { ToasterService } from '@abp/ng.theme.shared';
@ -170,19 +170,19 @@ export class CustomToasterService implements Toaster.Service {
``` ```
```js ```js
// app.module.ts // app.config.ts
import { ToasterService } from '@abp/ng.theme.shared'; import { ToasterService } from '@abp/ng.theme.shared';
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
// ... // ...
{ {
provide: ToasterService, provide: ToasterService,
useClass: CustomToasterService, useClass: CustomToasterService,
}, },
] ],
}) };
``` ```
## API ## API

BIN
docs/en/images/angular-folder-structure.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 94 KiB

42
docs/en/modules/account-pro.md

@ -301,47 +301,41 @@ See the `AccountPermissions` class members for all permissions defined for this
#### Installation #### Installation
In order to configure the application to use the `AccountPublicModule` and the `AccountAdminModule`, you first need to import `AccountPublicConfigModule` from `@volo/abp.ng.account/public/config` and `AccountAdminConfigModule` from `@volo/abp.ng.account/admin/config` to root module. Config modules has a static `forRoot` method which you should call for a proper configuration. In order to configure the application to use the public account module and the admin account module, you first need to import `provideAccountPublicConfig` from `@volo/abp.ng.account/public/config` and `provideAccountAdminConfig` from `@volo/abp.ng.account/admin/config`. Then, you will need to append them to the `appConfig` array.
```js ```js
// app.module.ts // app.config.ts
import { AccountAdminConfigModule } from '@volo/abp.ng.account/admin/config'; import { provideAccountPublicConfig } from '@volo/abp.ng.account/public/config';
import { AccountPublicConfigModule } from '@volo/abp.ng.account/public/config'; import { provideAccountAdminConfig } from '@volo/abp.ng.account/admin/config';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
// other imports // ...
AccountPublicConfigModule.forRoot(), provideAccountAdminConfig(),
AccountAdminConfigModule.forRoot(), provideAccountPublicConfig(),
// other imports
], ],
// ... };
})
export class AppModule {}
``` ```
The `AccountPublicModule` should be imported and lazy-loaded in your routing module. It has a static `forLazy` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.account/public`. The account public package should be imported and lazy-loaded in your routing array. It has a static `createRoutes` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.account/public`.
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [ export const APP_ROUTES: Routes = [
// other route definitions // ...
{ {
path: 'account', path: 'account',
loadChildren: () => loadChildren: () => import('@volo/abp.ng.account/public').then(c => c.createRoutes(/* options here */)),
import('@volo/abp.ng.account/public').then(m => m.AccountPublicModule.forLazy(/* options here */)),
}, },
]; ];
@NgModule(/* AppRoutingModule metadata */)
export class AppRoutingModule {}
``` ```
> If you have generated your project via the startup template, you do not have to do anything, because it already has the modules. > If you have generated your project via the startup template, you do not have to do anything, because it already has the necessary configurations.
<h4 id="h-account-module-options">Options</h4> <h4 id="h-account-module-options">Options</h4>
You can modify the look and behavior of the module pages by passing the following options to `AccountModule.forLazy` static method: You can modify the look and behavior of the module pages by passing the following options to `createRoutes` static method:
- **redirectUrl**: Default redirect URL after logging in. - **redirectUrl**: Default redirect URL after logging in.
- **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details. - **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details.

38
docs/en/modules/audit-logging-pro.md

@ -244,45 +244,39 @@ See the `AbpAuditLoggingPermissions` class members for all permissions defined f
#### Installation #### Installation
In order to configure the application to use the `AuditLoggingModule`, you first need to import `AuditLoggingConfigModule` from `@volo/abp.ng.audit-logging/config` to root module. `AuditLoggingConfigModule` has a static `forRoot` method which you should call for a proper configuration. In order to configure the application to use the audit logging module, you first need to import `provideAuditLoggingConfig` from `@volo/abp.ng.audit-logging/config` to root configuration. Then, you will need to append it to the `appConfig` array.
```js ```js
// app.module.ts // app.config.ts
import { AuditLoggingConfigModule } from '@volo/abp.ng.audit-logging/config'; import { provideAuditLoggingConfig } from '@volo/abp.ng.audit-logging/config';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
// other imports // ...
AuditLoggingConfigModule.forRoot(), provideAuditLoggingConfig(),
// other imports
], ],
// ... };
})
export class AppModule {}
``` ```
The `AuditLoggingModule` should be imported and lazy-loaded in your routing module. It has a static `forLazy` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.audit-logging`. The audit logging module should be imported and lazy-loaded in your routing array. It has a static `createRoutes` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.audit-logging`.
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [ export const APP_ROUTES: Routes = [
// other route definitions // ...
{ {
path: 'audit-logs', path: 'audit-logs',
loadChildren: () => loadChildren: () => import('@volo/abp.ng.audit-logging').then(c => c.createRoutes(/* options here */)),
import('@volo/abp.ng.audit-logging').then(m => m.AuditLoggingModule.forLazy(/* options here */)),
}, },
]; ];
@NgModule(/* AppRoutingModule metadata */)
export class AppRoutingModule {}
``` ```
> If you have generated your project via the startup template, you do not have to do anything, because it already has both `AuditLoggingConfigModule` and `AuditLoggingModule`. > If you have generated your project via the startup template, you do not have to do anything, because it already has both files configured.
<h4 id="h-audit-logging-module-options">Options</h4> <h4 id="h-audit-logging-module-options">Options</h4>
You can modify the look and behavior of the module pages by passing the following options to `AuditLoggingModule.forLazy` static method: You can modify the look and behavior of the module pages by passing the following options to `createRoutes` static method:
- **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details. - **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details.
- **toolbarActionContributors:** Changes page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details. - **toolbarActionContributors:** Changes page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details.

35
docs/en/modules/chat.md

@ -206,38 +206,33 @@ See the [connection strings](../framework/fundamentals/connection-strings.md) do
#### Installation #### Installation
In order to configure the application to use the `ChatModule`, you first need to import `ChatConfigModule` from `@volo/abp.ng.chat/config` to root module. `ChatConfigModule` has a static `forRoot` method which you should call for a proper configuration. In order to configure the application to use the chat module, you first need to import `provideChatConfig` from `@volo/abp.ng.chat/config` to root application confiuration. Then, you will need to append it to the `appConfig` array.
```js ```js
// app.module.ts // app.config.ts
import { ChatConfigModule } from '@volo/abp.ng.chat/config'; import { provideChatConfig } from '@volo/abp.ng.chat/config';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
// other imports // ...
ChatConfigModule.forRoot(), provideChatConfig(),
// other imports
], ],
// ... };
})
export class AppModule {}
``` ```
The `ChatModule` should be imported and lazy-loaded in your routing module. It has a static `forLazy` method for configuration. It is available for import from `@volo/abp.ng.chat`. The chat module should be imported and lazy-loaded in your routing array. It has a static `createRoutes` method for configuration. It is available for import from `@volo/abp.ng.chat`.
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [ const APP_ROUTES: Routes = [
// other route definitions // ...
{ {
path: 'chat', path: 'chat',
loadChildren: () => loadChildren: () =>
import('@volo/abp.ng.chat').then(m => m.ChatModule.forLazy(/* options here */)), import('@volo/abp.ng.chat').then(c => c.createRoutes(/* options here */)),
}, },
]; ];
@NgModule(/* AppRoutingModule metadata */)
export class AppRoutingModule {}
``` ```
#### Services / Models #### Services / Models

43
docs/en/modules/gdpr.md

@ -177,45 +177,46 @@ See the [connection strings](../framework/fundamentals/connection-strings.md) do
### Installation ### Installation
In order to configure the application to use the `GdprModule`, you first need to import `GdprConfigModule` from `@volo/abp.ng.gdpr/config` to the root module. `GdprConfigModule` has a static `forRoot` method which you should call for a proper configuration. In order to configure the application to use the gdpr module, you first need to import `provideGdprConfig` from `@volo/abp.ng.gdpr/config` to the root configuration. Then, you will need to append it to the `appConfig` array.
```js ```js
// app.module.ts // app.config.ts
import { GdprConfigModule } from '@volo/abp.ng.gdpr/config'; import {
provideGdprConfig,
@NgModule({ withCookieConsentOptions,
imports: [ } from '@volo/abp.ng.gdpr/config';
// other imports
GdprConfigModule.forRoot(), export const appConfig: ApplicationConfig = {
// other imports providers: [
provideGdprConfig(
withCookieConsentOptions({
cookiePolicyUrl: '/gdpr-cookie-consent/cookie',
privacyPolicyUrl: '/gdpr-cookie-consent/privacy',
}),
),
], ],
// ... };
})
export class AppModule {}
``` ```
The `GdprModule` should be imported and lazy-loaded in your routing module. It has a static `forLazy` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.gdpr`. The gdpr module should be imported and lazy-loaded in your routing array. It has a static `createRoutes` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.gdpr`.
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [ const APP_ROUTES: Routes = [
// other route definitions // other route definitions
{ {
path: 'gdpr', path: 'gdpr',
loadChildren: () => loadChildren: () =>
import('@volo/abp.ng.gdpr').then(m => m.GdprModule.forLazy(/* options here */)), import('@volo/abp.ng.gdpr').then(c => c.createRoutes(/* options here */)),
}, },
]; ];
@NgModule(/* AppRoutingModule metadata */)
export class AppRoutingModule {}
``` ```
> If you have generated your project via the startup template, you do not have to do anything, because it already has both `GdprConfigModule` and `GdprModule`. > If you have generated your project via the startup template, you do not have to do anything, because it already has both files configured.
<h4 id="h-gdpr-module-options">Options</h4> <h4 id="h-gdpr-module-options">Options</h4>
You can modify the look and behavior of the module pages by passing the following options to the `GdprModule.forLazy` static method: You can modify the look and behavior of the module pages by passing the following options to the `createRoutes` static method:
- **entityActionContributors:** Changes the grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details. - **entityActionContributors:** Changes the grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details.
- **toolbarActionContributors:** Changes the page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details. - **toolbarActionContributors:** Changes the page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details.

38
docs/en/modules/identity-pro.md

@ -343,45 +343,39 @@ See the `IdentityPermissions` class members for all permissions defined for this
#### Installation #### Installation
In order to configure the application to use the `IdentityModule`, you first need to import `IdentityConfigModule` from `@volo/abp.ng.identity/config` to root module. `IdentityConfigModule` has a static `forRoot` method which you should call for a proper configuration. In order to configure the application to use the identity module, you first need to import `provideIdentityConfig` from `@volo/abp.ng.identity/config` to root configuration. Then, you will need to append it to the `appConfig` array.
```js ```js
// app.module.ts // app.config.ts
import { IdentityConfigModule } from '@volo/abp.ng.identity/config'; import { provideIdentityConfig } from '@volo/abp.ng.identity/config';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
// other imports // ...
IdentityConfigModule.forRoot(), provideIdentityConfig(),
// other imports
], ],
// ... };
})
export class AppModule {}
``` ```
The `IdentityModule` should be imported and lazy-loaded in your routing module. It has a static `forLazy` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.identity`. The identity module should be imported and lazy-loaded in your routing configuration. It has a static `createRoutes` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.identity`.
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [ const APP_ROUTES: Routes = [
// other route definitions // ...
{ {
path: 'identity', path: 'identity',
loadChildren: () => loadChildren: () =>
import('@volo/abp.ng.identity').then(m => m.IdentityModule.forLazy(/* options here */)), import('@volo/abp.ng.identity').then(c => c.createRoutes(/* options here */)),
}, },
]; ];
@NgModule(/* AppRoutingModule metadata */)
export class AppRoutingModule {}
``` ```
> If you have generated your project via the startup template, you do not have to do anything, because it already has both `IdentityConfigModule` and `IdentityModule`. > If you have generated your project via the startup template, you do not have to do anything, because it already has both configurations added.
<h4 id="h-identity-module-options">Options</h4> <h4 id="h-identity-module-options">Options</h4>
You can modify the look and behavior of the module pages by passing the following options to `IdentityModule.forLazy` static method: You can modify the look and behavior of the module pages by passing the following options to `createRoutes` static method:
- **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details. - **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details.
- **toolbarActionContributors:** Changes page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details. - **toolbarActionContributors:** Changes page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details.

36
docs/en/modules/identity-server-pro.md

@ -245,45 +245,39 @@ See the `AbpIdentityServerPermissions` class members for all permissions defined
#### Installation #### Installation
In order to configure the application to use the `IdentityServerModule`, you first need to import `IdentityServerConfigModule` from `@volo/abp.ng.identity-server/config` to root module. `IdentityServerConfigModule` has a static `forRoot` method which you should call for a proper configuration. In order to configure the application to use the identity server, you first need to import `provideIdentityServerConfig` from `@volo/abp.ng.identity-server/config` to root configuration. Then, you will need to append it to the `appConfig` array.
```js ```js
// app.module.ts // app.config.ts
import { IdentityServerConfigModule } from '@volo/abp.ng.identity-server/config'; import { provideIdentityServerConfig } from '@volo/abp.ng.identity-server/config';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
// other imports // ...
IdentityServerConfigModule.forRoot(), provideIdentityServerConfig()
// other imports
], ],
// ... };
})
export class AppModule {}
``` ```
The `IdentityServerModule` should be imported and lazy-loaded in your routing module. It has a static `forLazy` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.identity-server`. The identity server module should be imported and lazy-loaded in your routing module. It has a static `creatRoutes` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.identity-server`.
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [ const APP_ROUTES: Routes = [
// other route definitions // other route definitions
{ {
path: 'identity-server', path: 'identity-server',
loadChildren: () => loadChildren: () =>
import('@volo/abp.ng.identity-server').then(m => m.IdentityServerModule.forLazy(/* options here */)), import('@volo/abp.ng.identity-server').then(c => c.createRoutes(/* options here */)),
}, },
]; ];
@NgModule(/* AppRoutingModule metadata */)
export class AppRoutingModule {}
``` ```
> If you have generated your project via the startup template, you do not have to do anything, because it already has both `IdentityServerConfigModule` and `IdentityServerModule`. > If you have generated your project via the startup template, you do not have to do anything, because it already has both files configured.
<h4 id="h-identity-server-module-options">Options</h4> <h4 id="h-identity-server-module-options">Options</h4>
You can modify the look and behavior of the module pages by passing the following options to `IdentityServerModule.forLazy` static method: You can modify the look and behavior of the module pages by passing the following options to `createRoutes` static method:
- **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details. - **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details.
- **toolbarActionContributors:** Changes page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details. - **toolbarActionContributors:** Changes page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details.

40
docs/en/modules/language-management.md

@ -149,45 +149,41 @@ See the `LanguageManagementPermissions` class members for all permissions define
#### Installation #### Installation
To configure the application to use the `LanguageManagementModule`, you first need to import `LanguageManagementConfigModule` from `@volo/abp.ng.language-management/config` to root module. `LanguageManagementConfigModule` has a static `forRoot` method which you should call for a proper configuration. To configure the application to use the language management module, you first need to import `provideLanguageManagementConfig` from `@volo/abp.ng.language-management/config` to root configuration. Then, you will need to append it to the `appConfig` array.
```js ```js
// app.module.ts // app.config.ts
import { LanguageManagementConfigModule } from '@volo/abp.ng.language-management/config'; import { provideLanguageManagementConfig } from '@volo/abp.ng.language-management/config';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
// other imports // ...
LanguageManagementConfigModule.forRoot(), provideLanguageManagementConfig()
// other imports
], ],
// ... };
})
export class AppModule {}
``` ```
The `LanguageManagementModule` should be imported and lazy-loaded in your routing module. It has a static `forLazy` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.language-management`. The language management module should be imported and lazy-loaded in your routing array. It has a static `createRoutes` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.language-management`.
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [
// other route definitions const APP_ROUTES: Routes = [
// ...
{ {
path: 'language-management', path: 'language-management',
loadChildren: () => loadChildren: () =>
import('@volo/abp.ng.language-management').then(m => m.LanguageManagementModule.forLazy(/* options here */)), import('@volo/abp.ng.language-management').then(c => c.createRoutes(/* options here */)),
}, },
]; ];
@NgModule(/* AppRoutingModule metadata */)
export class AppRoutingModule {}
``` ```
> If you have generated your project via the startup template, you do not have to do anything because it already has both `LanguageManagementConfigModule` and `LanguageManagementModule`. > If you have generated your project via the startup template, you do not have to do anything because it already has both configurations implemented.
<h4 id="h-language-management-module-options">Options</h4> <h4 id="h-language-management-module-options">Options</h4>
You can modify the look and behavior of the module pages by passing the following options to `LanguageManagementModule.forLazy` static method: You can modify the look and behavior of the module pages by passing the following options to `createRoutes` static method:
- **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details. - **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details.
- **toolbarActionContributors:** Changes page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details. - **toolbarActionContributors:** Changes page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details.

34
docs/en/modules/payment.md

@ -81,38 +81,36 @@ This page is used to send Name, Surname and Email Address of user to PayU.
#### Installation #### Installation
In order to configure the application to use the `PaymentModule`, you first need to import `PaymentAdminConfigModule` from `@volo/abp.ng.payment/admin/config` to the root module. `PaymentAdminConfigModule` has a static `forRoot` method which you should call for a proper configuration: In order to configure the application to use the payment module, you first need to import `PaymentAdminConfigModule` from `@volo/abp.ng.payment/admin/config` to the root configuration. `PaymentAdminConfigModule` has a static `forRoot` method which you should call for a proper configuration:
```js ```js
// app.module.ts // app.config.ts
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import { PaymentAdminConfigModule } from '@volo/abp.ng.payment/admin/config'; import { PaymentAdminConfigModule } from '@volo/abp.ng.payment/admin/config';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
// other imports // ...
PaymentAdminConfigModule.forRoot(), importProvidersFrom([
// other imports PaymentAdminConfigModule.forRoot()
]),
], ],
// ... };
})
export class AppModule {}
``` ```
The `PaymentAdminModule` should be imported and lazy-loaded in your routing module as below: The payment admin module should be imported and lazy-loaded in your routing array as below:
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [ const APP_ROUTES: Routes = [
// other route definitions // ...
{ {
path: 'payment', path: 'payment',
loadChildren: () => loadChildren: () =>
import('@volo/abp.ng.payment/admin').then(m => m.PaymentAdminModule.forLazy()), import('@volo/abp.ng.payment/admin').then(c => c.createRoutes()),
}, },
]; ];
@NgModule(/* AppRoutingModule metadata */)
export class AppRoutingModule {}
``` ```
#### Payment plans page #### Payment plans page

38
docs/en/modules/saas.md

@ -244,45 +244,39 @@ See the `SaasHostPermissions` class members for all permissions defined for this
#### Installation #### Installation
In order to configure the application to use the `SaasModule`, you first need to import `SaasConfigModule` from `@volo/abp.ng.saas/config` to root module. `SaasConfigModule` has a static `forRoot` method which you should call for a proper configuration. In order to configure the application to use the saas module, you first need to import `provideSaasConfig` from `@volo/abp.ng.saas/config` to root module. Then, you will need to append it to the `appConfig` array.
```js ```js
// app.module.ts // app.config.ts
import { SaasConfigModule } from '@volo/abp.ng.saas/config'; import { provideSaasConfig } from '@volo/abp.ng.saas/config';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
// other imports // ...
SaasConfigModule.forRoot(), provideSaasConfig(),
// other imports
], ],
// ... };
})
export class AppModule {}
``` ```
The `SaasModule` should be imported and lazy-loaded in your routing module. It has a static `forLazy` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.saas`. The saas module should be imported and lazy-loaded in your routing configuration. It has a static `createRoutes` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.saas`.
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [ const APP_ROUTES: Routes = [
// other route definitions // ...
{ {
path: 'saas', path: 'saas',
loadChildren: () => loadChildren: () =>
import('@volo/abp.ng.saas').then(m => m.SaasModule.forLazy(/* options here */)), import('@volo/abp.ng.saas').then(c => c.createRoutes(/* options here */)),
}, },
]; ];
@NgModule(/* AppRoutingModule metadata */)
export class AppRoutingModule {}
``` ```
> If you have generated your project via the startup template, you do not have to do anything, because it already has both `SaasConfigModule` and `SaasModule`. > If you have generated your project via the startup template, you do not have to do anything, because it already has both configurations implemented.
<h4 id="h-saas-module-options">Options</h4> <h4 id="h-saas-module-options">Options</h4>
You can modify the look and behavior of the module pages by passing the following options to `SaasModule.forLazy` static method: You can modify the look and behavior of the module pages by passing the following options to `createRoutes` static method:
- **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details. - **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details.
- **toolbarActionContributors:** Changes page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details. - **toolbarActionContributors:** Changes page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details.

38
docs/en/modules/text-template-management.md

@ -162,45 +162,39 @@ See the `TextTemplateManagementPermissions` class members for all permissions de
#### Installation #### Installation
In order to configure the application to use the `TextTemplateManagementModule`, you first need to import `TextTemplateManagementConfigModule` from `@volo/abp.ng.text-template-management/config` to root module. `TextTemplateManagementConfigModule` has a static `forRoot` method which you should call for a proper configuration. In order to configure the application to use the text template management module, you first need to import `provideTextTemplateManagementConfig` from `@volo/abp.ng.text-template-management/config` to root configuration. Then, you will need to append it to the `appConfig` array.
```js ```js
// app.module.ts // app.config.ts
import { TextTemplateManagementConfigModule } from '@volo/abp.ng.text-template-management/config'; import { provideTextTemplateManagementConfig } from '@volo/abp.ng.text-template-management/config';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
// other imports // ...
TextTemplateManagementConfigModule.forRoot(), provideTextTemplateManagementConfig()
// other imports
], ],
// ... };
})
export class AppModule {}
``` ```
The `TextTemplateManagementModule` should be imported and lazy-loaded in your routing module. It has a static `forLazy` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.text-template-management`. The text template management module should be imported and lazy-loaded in your routing array. It has a static `createRoutes` method for configuration. Available options are listed below. It is available for import from `@volo/abp.ng.text-template-management`.
```js ```js
// app-routing.module.ts // app.routes.ts
const routes: Routes = [ const APP_ROUTES: Routes = [
// other route definitions // ...
{ {
path: 'text-template-management', path: 'text-template-management',
loadChildren: () => loadChildren: () =>
import('@volo/abp.ng.text-template-management').then(m => m.TextTemplateManagementModule.forLazy(/* options here */)), import('@volo/abp.ng.text-template-management').then(c => c.createRoutes(/* options here */)),
}, },
]; ];
@NgModule(/* AppRoutingModule metadata */)
export class AppRoutingModule {}
``` ```
> If you have generated your project via the startup template, you do not have to do anything, because it already has both `TextTemplateManagementConfigModule` and `TextTemplateManagementModule`. > If you have generated your project via the startup template, you do not have to do anything, because it already has both configurations implemented.
<h4 id="h-text-template-management-module-options">Options</h4> <h4 id="h-text-template-management-module-options">Options</h4>
You can modify the look and behavior of the module pages by passing the following options to `TextTemplateManagementModule.forLazy` static method: You can modify the look and behavior of the module pages by passing the following options to `createRoutes` static method:
- **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details. - **entityActionContributors:** Changes grid actions. Please check [Entity Action Extensions for Angular](../framework/ui/angular/entity-action-extensions.md) for details.
- **toolbarActionContributors:** Changes page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details. - **toolbarActionContributors:** Changes page toolbar. Please check [Page Toolbar Extensions for Angular](../framework/ui/angular/page-toolbar-extensions.md) for details.

38
docs/en/solution-templates/application-module/index.md

@ -183,45 +183,29 @@ The issue management page is empty in the beginning. You may change the content
Now, let's have a closer look at some key elements of your project. Now, let's have a closer look at some key elements of your project.
### The Main Module ### The Main Component
`IssueManagementModule` at the _angular/projects/issue-management/src/lib/issue-management.module.ts_ path is the main module of your module project. There are a few things worth mentioning in it: `IssueManagementComponent` at the _angular/projects/issue-management/src/lib/issue-management.routes.ts_ path is the main component of your module project. There are a few things worth mentioning in it:
- Essential ABP modules, i.e. `CoreModule` and `ThemeSharedModule`, are imported. - `IssueManagementComponent` is declared as standalone within the latest migration.
- `IssueManagementRoutingModule` is imported. - `ISSUE_MANAGEMENT_ROUTES` is configured to be lazy-loaded.
- `IssueManagementComponent` is declared.
- It is prepared for configurability. The `forLazy` static method enables [a configuration to be passed to the module when it is loaded by the router](https://volosoft.com/blog/how-to-configure-angular-modules-loaded-by-the-router).
### The Main Routing Module
`IssueManagementRoutingModule` at the _angular/projects/issue-management/src/lib/issue-management-routing.module.ts_ path is the main routing module of your module project. It currently does two things:
- Loads `DynamicLayoutComponent` at base path it is given.
- Loads `IssueManagementComponent` as child to the layout, again at the given base path.
You can rearrange this module to load more than one component at different routes, but you need to update the route provider at _angular/projects/issue-management/config/src/providers/route.provider.ts_ to match the new routing structure with the routes in the menu. Please check [Modifying the Menu](../../framework/ui/angular/modifying-the-menu.md) to see how route providers work.
### The Config Module ### The Config Module
There is a config module at the _angular/projects/issue-management/config/src/issue-management-config.module.ts_ path. The static `forRoot` method of this module is supposed to be called at the route level. So, you may assume the following will take place: There is a config module at the _angular/projects/issue-management/config/src/providers/route.provider.ts_ path. The static `provideIssueManagement` method of this module is supposed to be called at the route level. So, you may assume the following will take place:
```js ```js
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [ providers: [
/* other imports */ // ...
provideIssueManagement(),
IssueManagementConfigModule.forRoot(), // ...
], ],
};
/* rest of the module meta data */
})
export class AppModule {}
``` ```
You can use this static method to configure an application that uses your module project. An example of such configuration is already implemented and the `ISSUE_MANAGEMENT_ROUTE_PROVIDERS` token is provided here. The method can take options which enables further configuration possibilities. You can use this static method to configure an application that uses your module project. An example of such configuration is already implemented and the `ISSUE_MANAGEMENT_ROUTE_PROVIDERS` token is provided here. The method can take options which enables further configuration possibilities.
The difference between the `forRoot` method of the config module and the `forLazy` method of the main module is that, for smallest bundle size, the former should only be used when you have to configure an app before your module is even loaded.
### Testing Angular UI ### Testing Angular UI

BIN
docs/en/solution-templates/layered-web-application/images/angular-folder-structure.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 88 KiB

BIN
docs/en/solution-templates/layered-web-application/images/angular-template-structure-diagram.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 62 KiB

26
docs/en/solution-templates/layered-web-application/web-applications.md

@ -49,25 +49,25 @@ The Angular application runs as a client-side SPA in the user's browser and comm
![angular-folder-structure](images/angular-folder-structure.png) ![angular-folder-structure](images/angular-folder-structure.png)
Each of ABP modules is an NPM package. Some ABP modules are added as a dependency in `package.json`. These modules install with their dependencies. To see all ABP packages, you can run the following command in the `angular` folder: Each of ABP module is an NPM package. Some ABP modules are added as a dependency in `package.json`. These modules are installed with their dependencies. To see all ABP packages, you can run the following command in the `angular` folder:
```bash ```bash
yarn list --pattern abp yarn list --pattern abp
``` ```
Angular application module structure: Angular application structure:
![Angular template structure diagram](images/angular-template-structure-diagram.png) ![Angular template structure diagram](images/angular-template-structure-diagram.png)
### AppModule ### Application Config
`AppModule` is the root module of the application. Some of the ABP modules and some essential modules are imported to `AppModule`. Application config is the root configuration of the application. Some of the ABP modules and some essential providers are imported to `appConfig`.
ABP Config modules have also been imported to `AppModule` for initial requirements of the lazy-loadable ABP modules. ABP Config modules have also been provided in `appConfig` for initial requirements of the lazy-loadable ABP modules.
### AppRoutingModule ### APP_ROUTES
There are lazy-loadable ABP modules in the `AppRoutingModule` as routes. There are lazy-loadable ABP modules in the `APP_ROUTES` as routes.
> Paths of ABP Modules should not be changed. > Paths of ABP Modules should not be changed.
@ -76,7 +76,7 @@ You should add `routes` property in the `data` object to add a link on the menu
```js ```js
{ {
path: 'dashboard', path: 'dashboard',
loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule), loadComponent: () => import('./dashboard/dashboard.component').then(c => c.DashboardComponent),
canActivate: [authGuard, permissionGuard], canActivate: [authGuard, permissionGuard],
data: { data: {
routes: { routes: {
@ -97,19 +97,13 @@ In the above example;
After the above `routes` definition, if the user is authorized, the dashboard link will appear on the menu. After the above `routes` definition, if the user is authorized, the dashboard link will appear on the menu.
### Shared Module
The modules that may be required for all modules have been imported to the `SharedModule`. You should import `SharedModule` to all modules.
See the [Sharing Modules](https://angular.io/guide/sharing-ngmodules) document.
### Environments ### Environments
The files under the `src/environments` folder have the essential configuration of the application. The files under the `src/environments` folder have the essential configuration of the application.
### Home Module ### Home Component
Home module is an example lazy-loadable module that loads on the root address of the application. Home component is an example lazy-loadable component that loads on the root address of the application.
### Styles ### Styles

9
docs/en/solution-templates/microservice/localization-system.md

@ -92,12 +92,12 @@ You can define new localization entries in the language files under the **Locali
Angular UI gets the localization resources from the [`application-localization`](../../framework/api-development/standard-apis/localization.md) API's response and merges these resources in the `ConfigStateService` for the localization entries/resources coming from the backend side. Angular UI gets the localization resources from the [`application-localization`](../../framework/api-development/standard-apis/localization.md) API's response and merges these resources in the `ConfigStateService` for the localization entries/resources coming from the backend side.
In addition, you may need to define some localization entries and only use them on the UI side. ABP already provides the related configuration for you, so you don't need to make any configurations related to that and instead you can directly define localization entries in the `app.-module.ts` file of your angular application as follows: In addition, you may need to define some localization entries and only use them on the UI side. ABP already provides the related configuration for you, so you don't need to make any configurations related to that and instead you can directly define localization entries in the `app.config.ts` file of your angular application as follows:
```ts ```ts
import { provideAbpCore, withOptions } from '@abp/ng.core'; import { provideAbpCore, withOptions } from '@abp/ng.core';
@NgModule({ export const appConfig: ApplicationConfig = {
providers: [ providers: [
// ... // ...
provideAbpCore( provideAbpCore(
@ -119,11 +119,8 @@ import { provideAbpCore, withOptions } from '@abp/ng.core';
] ]
}), }),
), ),
...
], ],
}) };
export class AppModule {}
``` ```
After defining the localization entries, it can be used as below: After defining the localization entries, it can be used as below:

34
docs/en/suite/solution-structure.md

@ -226,25 +226,21 @@ Angular application folder structure looks like below:
![angular-folder-structure](../images/angular-folder-structure.png) ![angular-folder-structure](../images/angular-folder-structure.png)
Each of ABP modules is an NPM package. Some ABP modules are added as a dependency in `package.json`. These modules install with their dependencies. To see all ABP packages, you can run the following command in the `angular` folder: Each of ABP module is an NPM package. Some ABP modules are added as a dependency in `package.json`. These modules are installed with their dependencies. To see all ABP packages, you can run the following command in the `angular` folder:
```bash ```bash
yarn list --pattern abp yarn list --pattern abp
``` ```
Angular application module structure: ### Application Config
![Angular template structure diagram](../images/angular-template-structure-diagram.png) Application config is the root module of the application. Some of ABP modules and some essential modules are imported to the `appConfig`.
### AppModule ABP Config modules also have been imported to `appConfig`  for initially requirements of lazy-loadable ABP modules.
`AppModule` is the root module of the application. Some of ABP modules and some essential modules imported to the `AppModule`. ### APP_ROUTES
ABP Config modules also have imported to `AppModule`  for initially requirements of lazy-loadable ABP modules. There are lazy-loadable ABP modules in the `APP_ROUTES` as routes.
### AppRoutingModule
There are lazy-loadable ABP modules in the `AppRoutingModule` as routes.
> Paths of ABP Modules should not be changed. > Paths of ABP Modules should not be changed.
@ -253,7 +249,7 @@ You should add `routes` property in the `data` object to add a link on the menu
```js ```js
{ {
path: 'dashboard', path: 'dashboard',
loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule), loadComponent: () => import('./dashboard/dashboard.component').then(c => c.DashboardComponent),
canActivate: [authGuard, permissionGuard], canActivate: [authGuard, permissionGuard],
data: { data: {
routes: { routes: {
@ -274,25 +270,19 @@ In the above example;
After the above `routes` definition, if the user is authorized, the dashboard link will appear on the menu. After the above `routes` definition, if the user is authorized, the dashboard link will appear on the menu.
### Shared Module
The modules that may be required for all modules have imported to the `SharedModule`. You should import the `SharedModule` to all modules.
See the [Sharing Modules](https://angular.io/guide/sharing-ngmodules) document.
### Environments ### Environments
The files under the `src/environments` folder has the essential configuration of the application. The files under the `src/environments` folder has the essential configuration of the application.
### Home Module ### Home Component
Home module is an example lazy-loadable module that loads on the root address of the application. Home component is an example lazy-loadable standalone component that loads on the root address of the application.
### Dashboard Module ### Dashboard Component
Dashboard module is a lazy-loadable module. `HostDashboardComponent` and `TenantDashboardComponent` declared to this module. One of these components is shown according to the user's authorization. Dashboard component is a lazy-loadable component. `HostDashboardComponent` and `TenantDashboardComponent` are declared within this root component. One of these components is shown according to authorization of the user.
There are four widgets in the `HostDashboardComponent` which declared in ABP modules. There are four widgets in the `HostDashboardComponent` which are declared in ABP modules.
### Styles ### Styles

103
docs/en/tutorials/microservice/part-05.md

@ -516,14 +516,6 @@ abp generate-proxy -t ng -m ordering -u http://localhost:44311 --target ordering
For more information, please refer to the [Service Proxies](https://abp.io/docs/latest/framework/ui/angular/service-proxies) documentation. For more information, please refer to the [Service Proxies](https://abp.io/docs/latest/framework/ui/angular/service-proxies) documentation.
### Create Order Module
Run the following command line to create a new module, named `OrderModule` in the root folder of the angular application:
```bash
yarn ng generate module order --module ordering-service --project ordering-service --routing --route orders
```
### Add Order Route ### Add Order Route
* Create `order-base.routes.ts` file under the `projects/ordering-service/config/src/providers` folder and add the following code: * Create `order-base.routes.ts` file under the `projects/ordering-service/config/src/providers` folder and add the following code:
@ -565,39 +557,102 @@ function configureRoutes() {
routesService.add(routes); routesService.add(routes);
} }
``` ```
* Open the `projects/ordering-service/config/src/providers/route.provider.ts` file and add `ORDERS_ORDER_ROUTE_PROVIDER` to the `ORDER_SERVICE_PROVIDERS` array as following code:
* Open the `projects/ordering-service/config/src/ordering-service-config.module.ts` file and add `ORDERS_ORDER_ROUTE_PROVIDER` to the `providers` array as following code: *route.provider.ts*
*ordering-service-config.module.ts*
```typescript ```typescript
import { ModuleWithProviders, NgModule } from '@angular/core'; import { eLayoutType, RoutesService } from '@abp/ng.core';
import { ORDERING_SERVICE_ROUTE_PROVIDERS } from './providers/route.provider'; import {
import { ORDERS_ORDER_ROUTE_PROVIDER } from './providers/order-route.provider'; EnvironmentProviders,
inject,
@NgModule() makeEnvironmentProviders,
export class OrderingServiceConfigModule { provideAppInitializer,
static forRoot(): ModuleWithProviders<OrderingServiceConfigModule> { } from '@angular/core';
return { import { eOrderingServiceRouteNames } from '../enums/route-names';
ngModule: OrderingServiceConfigModule, import { ORDERS_ORDER_ROUTE_PROVIDER } from './order-route.provider';
providers: [ORDERING_SERVICE_ROUTE_PROVIDERS, ORDERS_ORDER_ROUTE_PROVIDER],
};
} export const ORDER_SERVICE_ROUTE_PROVIDERS = [
provideAppInitializer(() => {
configureRoutes();
}),
];
export function configureRoutes() {
const routesService = inject(RoutesService);
routesService.add([
{
path: '/order-service',
name: eOrderingServiceRouteNames.OrderService,
iconClass: 'fas fa-book',
layout: eLayoutType.application,
order: 3,
},
]);
}
const ORDER_SERVICE_PROVIDERS: EnvironmentProviders[] = [
...ORDER_SERVICE_ROUTE_PROVIDERS,
...ORDERS_ORDER_ROUTE_PROVIDER
];
export function provideOrderService() {
return makeEnvironmentProviders(ORDER_SERVICE_PROVIDERS);
} }
``` ```
* Do not forget adding `provideOrderService()` to the providers inside `app.config.ts` as follows:
```typescript
import { provideOrderService } from '@order-service/config';
export const appConfig: ApplicationConfig = {
providers: [
// ...
provideOrderService()
],
};
```
* Lastly, you need to update the `APP_ROUTES` array in `app.routes.ts` file as follows:
```typescript
// app.routes.ts
export const APP_ROUTES: Routes = [
// ...
{
path: 'order-service',
children: ORDER_SERVICE_ROUTES,
},
];
```
```typescript
// order-service.routes.ts
export const ORDER_SERVICE_ROUTES: Routes = [
{
path: '',
pathMatch: 'full',
component: RouterOutletComponent,
},
{ path: 'orders', children: ORDER_ROUTES },
];
```
### Create Order Page ### Create Order Page
* Create `order.component.ts` file under the `projects/ordering-service/src/lib/order` folder as following code: * Create `order.component.ts` file under the `projects/ordering-service/src/lib/order` folder as following code:
```typescript ```typescript
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { OrderDto, OrderService } from './proxy/ordering-service/services'; import { OrderDto, OrderService } from './proxy/ordering-service/services';
@Component({ @Component({
selector: 'lib-order', selector: 'lib-order',
standalone: false,
templateUrl: './order.component.html', templateUrl: './order.component.html',
styleUrl: './order.component.css' styleUrl: './order.component.css'
imports: [CommonModule]
}) })
export class OrderComponent { export class OrderComponent {

39
docs/en/ui-themes/lepton-x-lite/angular.md

@ -31,42 +31,33 @@ yarn add bootstrap-icons
Note: You should remove the old theme styles from "angular.json" if you are switching from "ThemeBasic" or "Lepton." Note: You should remove the old theme styles from "angular.json" if you are switching from "ThemeBasic" or "Lepton."
Look at the [Theme Configurations](../../framework/ui/angular/theme-configurations.md) list of styles. Depending on your theme, you can alter your styles in angular.json. Look at the [Theme Configurations](../../framework/ui/angular/theme-configurations.md) list of styles. Depending on your theme, you can alter your styles in angular.json.
- Finally, remove `ThemeBasicModule`, `provideThemeBasicConfig` from `app.module.ts`, and import the related modules in `app.module.ts` - Finally, remove `provideThemeBasicConfig` from `app.config.ts`, and import the related providers in `app.config.ts`
```js ```js
import { ThemeLeptonXModule } from "@abp/ng.theme.lepton-x"; import { provideThemeLeptonX } from "@abp/ng.theme.lepton-x";
import { provideSideMenuLayout } from "@abp/ng.theme.lepton-x/layouts";
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [
// ...
// do not forget to remove ThemeBasicModule or other old theme module
// ThemeBasicModule
ThemeLeptonXModule.forRoot()
],
providers: [ providers: [
// do not forget to remove provideThemeBasicConfig or other old theme providers // ...
// provideThemeBasicConfig provideSideMenuLayout(),
provideThemeLeptonX(),
], ],
// ... };
})
export class AppModule {}
``` ```
Note: If you employ [Resource Owner Password Flow](../../framework/ui/angular/authorization.md#resource-owner-password-flow) for authorization, you should import the following module as well: Note: If you employ [Resource Owner Password Flow](../../framework/ui/angular/authorization.md#resource-owner-password-flow) for authorization, you should provide the following provider as well:
```js ```js
import { AccountLayoutModule } from "@abp/ng.theme.lepton-x/account"; import { provideAccountLayout } from "@abp/ng.theme.lepton-x/account";
@NgModule({ export const appConfig: ApplicationConfig = {
// ... providers: [
imports: [
// ...
AccountLayoutModule.forRoot(),
// ... // ...
provideAccountLayout()
], ],
// ... };
})
export class AppModule {}
``` ```
To change the logos and brand color of `LeptonX`, simply add the following CSS to the `styles.scss` To change the logos and brand color of `LeptonX`, simply add the following CSS to the `styles.scss`

57
docs/en/ui-themes/lepton-x/angular.md

@ -9,51 +9,36 @@ To add `LeptonX` into your existing projects, follow the steps below.
Add theme-specific styles into the `styles` array of the file. Check the [Theme Configurations](../../framework/ui/angular/theme-configurations.md#lepton-x-commercial) documentation for more information. Add theme-specific styles into the `styles` array of the file. Check the [Theme Configurations](../../framework/ui/angular/theme-configurations.md#lepton-x-commercial) documentation for more information.
Importing a CSS file as an ECMA module is not supported in Angular 14. Therefore, we need to add the styles in the angular.json file.
- At last, remove `ThemeLeptonModule` from `app.module.ts` and `shared.module.ts`, and import the following modules in `app.module.ts` - At last, remove `provideThemeLepton` from `app.config.ts`, and add the following providers in `app.config.ts`
```ts ```ts
import { import { provideThemeLeptonX } from '@volosoft/abp.ng.theme.lepton-x';
HttpErrorComponent, import { provideSideMenuLayout } from '@volosoft/abp.ng.theme.lepton-x/layouts';
ThemeLeptonXModule, // import { provideThemeLepton } from '@volo/abp.ng.theme.lepton';
} from "@volosoft/abp.ng.theme.lepton-x";
import { SideMenuLayoutModule } from "@volosoft/abp.ng.theme.lepton-x/layouts"; export const appConfig: ApplicationConfig = {
providers: [
@NgModule({ // provideThemeLepton() delete this
// ... provideSideMenuLayout(), // depends on which layout you choose
imports: [ provideThemeLeptonX(),
// ...
// ThemeLeptonModule.forRoot(), -> remove this line.
ThemeLeptonXModule.forRoot(),
SideMenuLayoutModule.forRoot(), // depends on which layout you choose
// ...
], ],
// ... };
})
export class AppModule {}
``` ```
If you want to use the **`Top Menu`** instead of the **`Side Menu`**, add TopMenuLayoutModule as below,and [this style imports](https://docs.abp.io/en/abp/7.4/UI/Angular/Theme-Configurations#lepton-x-commercial) If you want to use the **`Top Menu`** instead of the **`Side Menu`**, add `provideTopMenuLayout` as below,and [this style imports](https://docs.abp.io/en/abp/7.4/UI/Angular/Theme-Configurations#lepton-x-commercial)
```ts ```ts
import { import { provideThemeLeptonX } from '@volosoft/abp.ng.theme.lepton-x';
HttpErrorComponent, import { provideTopMenuLayout } from '@volosoft/abp.ng.theme.lepton-x/layouts';
ThemeLeptonXModule,
} from "@volosoft/abp.ng.theme.lepton-x"; export const appConfig: ApplicationConfig = {
import { TopMenuLayoutModule } from "@volosoft/abp.ng.theme.lepton-x/layouts"; providers: [
provideTopMenuLayout(),
@NgModule({ provideThemeLeptonX(),
// ...
imports: [
// ...
// ThemeLeptonModule.forRoot(), -> remove this line.
ThemeLeptonXModule.forRoot(),
TopMenuLayoutModule.forRoot(),
], ],
// ... };
})
export class AppModule {}
``` ```
- At this point, `LeptonX` theme should be up and running within your application. However, you may need to overwrite some css variables based your needs for every theme available as follows: - At this point, `LeptonX` theme should be up and running within your application. However, you may need to overwrite some css variables based your needs for every theme available as follows:

16
docs/en/ui-themes/lepton-x/angular/how-to-add-a-new-variation-to-lepton-x-for-angular.md

@ -37,26 +37,20 @@ export const NEW_THEME_PROVIDER = [
In this code snippet, we create a new instance of the LpxTheme class called myNewThemeDefinition. We specify the bundles that make up the theme (e.g., "bootstrap-custom" and "custom-theme"), the style name for the theme, a label to display in the UI, and an icon (using Bootstrap icons in this example). In this code snippet, we create a new instance of the LpxTheme class called myNewThemeDefinition. We specify the bundles that make up the theme (e.g., "bootstrap-custom" and "custom-theme"), the style name for the theme, a label to display in the UI, and an icon (using Bootstrap icons in this example).
### Step 2: Registering the New Theme Provider ### Step 2: Registering the New Theme Provider
Now that we have defined the new theme appearance, we need to register it as a provider in our Angular project. Open the app.module.ts file (or the module where LeptonX is configured), and add the following code: Now that we have defined the new theme appearance, we need to register it as a provider in our Angular project. Open the `app.config.ts` file (or the configuration where LeptonX is configured), and add the following code:
```js ```js
import { NEW_THEME_PROVIDER } from './new-theme.provider.ts'; import { NEW_THEME_PROVIDER } from './new-theme.provider.ts';
@NgModule({ export const appConfig: ApplicationConfig = {
imports: [
// ...
],
providers: [ providers: [
// ... // ...
NEW_THEME_PROVIDER, NEW_THEME_PROVIDER
], ],
// ... };
})
export class AppModule { }
``` ```
By importing the `NEW_THEME_PROVIDER` from the file where we defined our theme, we can add it to the providers array of our Angular module. This makes the new theme appearance available throughout the application. By importing the `NEW_THEME_PROVIDER` from the file where we defined our theme, we can add it to the providers array of our Angular application configuration. This makes the new theme appearance available throughout the application.
### Step 3: Adding the Styles Path to angular.json ### Step 3: Adding the Styles Path to angular.json

29
docs/en/ui-themes/lepton-x/angular/how-to-change-default-theme-option.md

@ -1,26 +1,25 @@
# Configuring the Default Theme for LeptonX # Configuring the Default Theme for LeptonX
The LeptonX theme offers multiple appearances to suit your application's visual style. You can easily configure the default theme for your application using the ThemeLeptonXModule provided by LeptonX. The LeptonX theme offers multiple appearances to suit your application's visual style. You can easily configure the default theme for your application using the `provideThemeLeptonX` provided by LeptonX.
### Configuration Code ### Configuration Code
To set the default theme, you need to configure the ThemeLeptonXModule using the forRoot() function in your application's main module (often referred to as AppModule). Here's an example: To set the default theme, you need to configure the `provideThemeLeptonX` using the `withThemeLeptonXOptions({...})` function in the main configuration of your application (often referred to as appConfig). Here's an example:
```js ```js
import { ThemeLeptonXModule } from 'leptonx'; // Import the LeptonX theme module import { provideThemeLeptonX, withThemeLeptonXOptions } from '@volosoft/abp.ng.theme.lepton-x';
@NgModule({ export const appConfig: ApplicationConfig = {
// ... Other module configurations providers: [
imports: [ // ...
// ... Other imported modules provideThemeLeptonX(
ThemeLeptonXModule.forRoot({ withThemeLeptonXOptions({
defaultTheme: 'light', // Set the default theme to 'light' defaultTheme: 'light'
}), })
),
], ],
bootstrap: [AppComponent], };
})
export class AppModule {}
``` ```
In the example above, we've imported the ThemeLeptonXModule and configured it using the forRoot() function. By providing the defaultTheme parameter and setting its value to 'light', In the example above, we've imported the `provideThemeLeptonX` and `withThemeLeptonXOptions`, then configured it using the option parameters. By providing the `defaultTheme` parameter and setting its value to 'light'.
If you delete the defaultTheme parameter in the configuration object, the LeptonX theme will use the default value of "System" as the default theme appearance. If you delete the defaultTheme parameter in the configuration object, the LeptonX theme will use the default value of "System" as the default theme appearance.

23
docs/en/ui-themes/lepton-x/how-to-use-lepton-x-components-with-angular-custom-layout.md

@ -5,25 +5,22 @@ First, The custom layout component should be created and implemented for the Ang
Related content can be found in the [Component Replacement Document](../../framework/ui/angular/component-replacement.md#how-to-replace-a-layout) Related content can be found in the [Component Replacement Document](../../framework/ui/angular/component-replacement.md#how-to-replace-a-layout)
After creating a custom layout, these imports should be imported in the `app.config.ts` file because the modules contain definitions of the Lepton X components.
After creating a custom layout, these imports should be imported in the `app.module.ts` file because the modules contain definitions of the Lepton X components.
```javascript ```javascript
// app.module.ts // app.config.ts
import { LpxSideMenuLayoutModule } from '@volosoft/ngx-lepton-x/layouts'; import { LpxSideMenuLayoutModule } from '@volosoft/ngx-lepton-x/layouts';
import { LpxResponsiveModule } from '@volo/ngx-lepton-x.core';// optional. Only, if you are using lpxResponsive directive import { LpxResponsiveModule } from '@volo/ngx-lepton-x.core';// optional. Only, if you are using lpxResponsive directive
@NgModule({ export const appConfig: ApplicationConfig = {
//... removed for clearity providers: [
imports: [ importProvidersFrom([
//... removed for clearity LpxSideMenuLayoutModule,
LpxSideMenuLayoutModule, LpxResponsiveModule // <-- Optional
LpxResponsiveModule // <-- Optional ])
] ],
}) };
export class AppModule {}
``` ```
Here is the simplified version of the `side-menu-layout.ts` file. Only the ABP Component Replacement code has been removed. Here is the simplified version of the `side-menu-layout.ts` file. Only the ABP Component Replacement code has been removed.

81
docs/en/ui-themes/lepton/customizing-lepton-theme.md

@ -12,19 +12,28 @@ You may want to change certain aspects of your website’s appearance with a cu
## Adding Custom Style ## Adding Custom Style
There is a `customStyle` boolean configuration in `ThemeLeptonModule`'s `forRoot` method. If this configuration is true, the style selection box is not included in the theme settings form and `ThemeLeptonModule` does not load its own styles. In this case, a custom style file must be added to the styles array in `angular.json` or must be imported by `style.scss`. There is a `customStyle` boolean configuration in `provideThemeLepton(withLeptonOptions({...}))` method. If this configuration is true, the style selection box is not included in the theme settings form and `theme-lepton` does not load its own styles. In this case, a custom style file must be added to the styles array in `angular.json` or must be imported by `style.scss`.
> Only angular project styles can be changed in this way. If the authorization flow is authorization code flow, MVC pages (login, profile, etc) are not affected by this change. > Only angular project styles can be changed in this way. If the authorization flow is authorization code flow, MVC pages (login, profile, etc) are not affected by this change.
Custom style implementation can be done with the following steps Custom style implementation can be done with the following steps
Set `customStyle` property to `true` where is `ThemeLeptonModule` imported with `forRoot` method. Set `customStyle` property to `true` where `provideThemeLepton(withLeptonOptions({...}))` method is called.
```javascript ```javascript
// app.module.ts // app.config.ts
ThemeLeptonModule.forRoot({ import { provideThemeLepton, withOptions as withLeptonOptions } from '@volo/abp.ng.theme.lepton';
customStyle: true
}) export const appConfig: ApplicationConfig = {
providers: [
// ...
provideThemeLepton(
withLeptonOptions({
customStyle: true
})
)
],
};
``` ```
Import your style file to `src/style.scss` Import your style file to `src/style.scss`
@ -68,7 +77,7 @@ Or add your style file to the `styles` arrays which in `angular.json` file
## Inserting Custom Content To Lepton Menu ## Inserting Custom Content To Lepton Menu
Lepton menu can take custom content both before and after the menu items displayed. In order to achieve this, pass a component as content through the parameters of `ThemeLeptonModule.forRoot` when you import the module in your root module, i.e. `AppModule`. Let's take a look at some examples. Lepton menu can take custom content both before and after the menu items displayed. In order to achieve this, pass a component as content through the parameters of `provideThemeLepton(withLeptonOptions({...}))` when you import the provider in your root app configuration, i.e. `appConfig`. Let's take a look at some examples.
### Placing Custom Content Before & After Menu Items ### Placing Custom Content Before & After Menu Items
@ -76,7 +85,10 @@ Lepton menu can take custom content both before and after the menu items display
First step is to create a component which will serve as the custom content. First step is to create a component which will serve as the custom content.
```js ```js
// ...
@Component({ @Component({
// ...
imports: [AsyncPipe],
template: `<a href="https://support.my-domain.com"> template: `<a href="https://support.my-domain.com">
<span class="lp-icon"><i class="fas fa-headset"></i></span> <span class="lp-icon"><i class="fas fa-headset"></i></span>
<span class="lp-text">Support Issues</span> <span class="lp-text">Support Issues</span>
@ -88,27 +100,23 @@ First step is to create a component which will serve as the custom content.
export class SupportLinkComponent { export class SupportLinkComponent {
issueCount$ = of(26); // dummy count, replace this with an actual service issueCount$ = of(26); // dummy count, replace this with an actual service
} }
@NgModule({
declarations: [SupportLinkComponent],
imports: [CommonModule],
})
export class SupportLinkModule {}
``` ```
Now, pass this component as `contentAfterRoutes` option to `ThemeLeptonModule`. Now, pass this component as `contentAfterRoutes` option to `provideThemeLepton(withLeptonOptions({...}))`.
```js ```js
@NgModule({ import { provideThemeLepton, withOptions as withLeptonOptions } from '@volo/abp.ng.theme.lepton';
imports: [
// other imports are removed for sake of brevity export const appConfig: ApplicationConfig = {
SupportLinkModule, providers: [
ThemeLeptonModule.forRoot({ // ...
contentAfterRoutes: [SupportLinkComponent], provideThemeLepton(
}) withLeptonOptions({
contentAfterRoutes: [SupportLinkComponent],
})
)
], ],
}) };
export class AppModule {}
``` ```
If you start the dev server, you must see the inserted content as follows: If you start the dev server, you must see the inserted content as follows:
@ -124,24 +132,25 @@ Placing the content before menu items is straightforward: Just replace `contentA
### Placing a Search Input Before Menu Items ### Placing a Search Input Before Menu Items
The Lepton package has a search component designed to work with the routes in the menu. You can simply import the module and pass the component as `contentBeforeRoutes` option to `ThemeLeptonModule`. The Lepton package has a search component designed to work with the routes in the menu. You can simply import the provider and pass the component as `contentBeforeRoutes` option to `provideThemeLepton(withLeptonOptions({...}))`.
```js ```js
import { MenuSearchComponent, MenuSearchModule } from '@volo/abp.ng.theme.lepton/extensions'; import { provideThemeLepton, withOptions as withLeptonOptions } from '@volo/abp.ng.theme.lepton';
import { MenuSearchComponent, provideMenuSearch } from '@volo/abp.ng.theme.lepton/extensions';
@NgModule({
imports: [ export const appConfig: ApplicationConfig = {
// other imports are removed for sake of brevity providers: [
// ...
MenuSearchModule.forRoot({ provideThemeLepton(
withLeptonOptions({
contentBeforeRoutes: [MenuSearchComponent],
})
),
provideMenuSearch({
limit: 3 // search result limit (default: Infinity) limit: 3 // search result limit (default: Infinity)
}),
ThemeLeptonModule.forRoot({
contentBeforeRoutes: [MenuSearchComponent],
}) })
], ],
}) };
export class AppModule {}
``` ```
Here is how the search input works: Here is how the search input works:

2
npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts

@ -103,7 +103,7 @@ export class DynamicLayoutComponent implements OnInit {
let message = `Layout ${layoutName} not found.`; let message = `Layout ${layoutName} not found.`;
if (layoutName === 'account') { if (layoutName === 'account') {
message = message =
'Account layout not found. Please check your configuration. If you are using LeptonX, please make sure you have added "AccountLayoutModule.forRoot()" to your app.module configuration.'; 'Account layout not found. Please check your configuration. If you are using LeptonX, please make sure you have added "provideAccountLayout()" to your app configuration.';
} }
console.warn(message); console.warn(message);
} }

Loading…
Cancel
Save