diff --git a/docs/en/UI/Angular/Title-Strategy-Service.md b/docs/en/UI/Angular/Title-Strategy-Service.md new file mode 100644 index 0000000000..64e94b3e17 --- /dev/null +++ b/docs/en/UI/Angular/Title-Strategy-Service.md @@ -0,0 +1,59 @@ +# Title Strategy For Angular + +## **ABP has a default title strategy for Angular UI**. + +This strategy is based on the title property. Provide a title property when setting a new route. + +**Example** + +```ts +{ + path: 'customers', + component: CustomersComponent, + title: 'AbpCustomers::Roles' +}, +``` + +- It is better to use localized text in the title property. It will be translated by **LocalizationService**. +- The **`title`** property is already set in **ABP internal packages**. + +## How it looks + +When you create a new route and provide a **`title`** property, it will look like this **` | <projectName>`** + +### What is `projectName` and How to Customize + +- **`projectName`** is the name of your application. By default, ABP sets a [**`projectName`**](https://github.com/abpframework/abp/blob/f48f78618a326644843c01424b093f0d79448769/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json#L4) for your application. This localization text is added for customization and can be changed for different languages. + +### Disable `projectName` + +- If you don't want to show **`projectName`** in the title, you can disable it. + +**app.module.ts** + +```ts +import { DISABLE_PROJECT_NAME } from '@abp/ng.core'; + +providers: [ + ..., + { provide: DISABLE_PROJECT_NAME, useValue: true} +], +``` + +- Now only title will be shown. + +## Override ABP's Default Title Strategy + +**app.module.ts** + +```ts +import { TitleStrategy } from '@angular/router'; +import { YourCustomStrategy } from './title-strategy.service.ts'; + +providers: [ + ..., + { provide: TitleStrategy, useExisting: YourCustomStrategy }, +], +``` + +- You can check [Angular Documentation](https://angular.io/api/router/TitleStrategy) to write a custom **`TitleStrategy`**. diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 8abc246509..d30322e277 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -1188,6 +1188,10 @@ { "text": "Abp Window Service", "path": "UI/Angular/Abp-Window-Service.md" + }, + { + "text": "Title Strategy", + "path": "UI/Angular/Title-Strategy-Service.md" } ] }, diff --git a/npm/ng-packs/packages/core/src/lib/core.module.ts b/npm/ng-packs/packages/core/src/lib/core.module.ts index eb475074ce..b77849d44c 100644 --- a/npm/ng-packs/packages/core/src/lib/core.module.ts +++ b/npm/ng-packs/packages/core/src/lib/core.module.ts @@ -24,7 +24,7 @@ import { ToInjectorPipe } from './pipes/to-injector.pipe'; import { CookieLanguageProvider } from './providers/cookie-language.provider'; import { LocaleProvider } from './providers/locale.provider'; import { LocalizationService } from './services/localization.service'; -import { OTHERS_GROUP } from './tokens'; +import { DISABLE_PROJECT_NAME, OTHERS_GROUP } from './tokens'; import { localizationContributor, LOCALIZATIONS } from './tokens/localization.token'; import { CORE_OPTIONS, coreOptionsFactory } from './tokens/options.token'; import { TENANT_KEY } from './tokens/tenant-key.token'; @@ -40,12 +40,11 @@ import { DefaultQueueManager } from './utils/queue'; import { IncludeLocalizationResourcesProvider } from './providers/include-localization-resources.provider'; import { SORT_COMPARE_FUNC, compareFuncFactory } from './tokens/compare-func.token'; import { AuthErrorFilterService } from './abstracts'; -import { DYNAMIC_LAYOUTS_TOKEN } from "./tokens/dynamic-layout.token"; -import { DEFAULT_DYNAMIC_LAYOUTS } from "./constants"; +import { DYNAMIC_LAYOUTS_TOKEN } from './tokens/dynamic-layout.token'; +import { DEFAULT_DYNAMIC_LAYOUTS } from './constants'; import { AbpTitleStrategy } from './services/title-strategy.service'; import { LocalStorageListenerService } from './services/local-storage-listener.service'; - const standaloneDirectives = [ AutofocusDirective, InputEventDebounceDirective, @@ -201,12 +200,16 @@ export class CoreModule { IncludeLocalizationResourcesProvider, { provide: DYNAMIC_LAYOUTS_TOKEN, - useValue: options.dynamicLayouts || DEFAULT_DYNAMIC_LAYOUTS + useValue: options.dynamicLayouts || DEFAULT_DYNAMIC_LAYOUTS, }, { provide: TitleStrategy, - useExisting: AbpTitleStrategy - } + useExisting: AbpTitleStrategy, + }, + { + provide: DISABLE_PROJECT_NAME, + useValue: options.disableProjectNameInTitle || false, + }, ], }; } diff --git a/npm/ng-packs/packages/core/src/lib/models/common.ts b/npm/ng-packs/packages/core/src/lib/models/common.ts index 714f2422c2..704fde958a 100644 --- a/npm/ng-packs/packages/core/src/lib/models/common.ts +++ b/npm/ng-packs/packages/core/src/lib/models/common.ts @@ -15,6 +15,7 @@ export namespace ABP { localizations?: Localization[]; othersGroup?: string; dynamicLayouts?: Map<string, string>; + disableProjectNameInTitle?: boolean; } export interface Child { diff --git a/npm/ng-packs/packages/core/src/lib/services/title-strategy.service.ts b/npm/ng-packs/packages/core/src/lib/services/title-strategy.service.ts index 4cb351918d..af961794f8 100644 --- a/npm/ng-packs/packages/core/src/lib/services/title-strategy.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/title-strategy.service.ts @@ -2,21 +2,18 @@ import { Injectable, effect, inject } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { TitleStrategy, RouterStateSnapshot } from '@angular/router'; import { Title } from '@angular/platform-browser'; -import { ConfigStateService } from './config-state.service'; import { LocalizationService } from './localization.service'; +import { DISABLE_PROJECT_NAME } from '../tokens'; @Injectable({ providedIn: 'root', }) export class AbpTitleStrategy extends TitleStrategy { protected readonly title = inject(Title); - protected readonly configState = inject(ConfigStateService); protected readonly localizationService = inject(LocalizationService); + protected readonly disableProjectName = inject(DISABLE_PROJECT_NAME, { optional: true }); protected routerState: RouterStateSnapshot; - projectName = toSignal(this.configState.getDeep$('localization.defaultResourceName'), { - initialValue: 'MyProjectName', - }); langugageChange = toSignal(this.localizationService.languageChange$); constructor() { @@ -30,14 +27,22 @@ export class AbpTitleStrategy extends TitleStrategy { override updateTitle(routerState: RouterStateSnapshot) { this.routerState = routerState; - let title = this.buildTitle(routerState); + const title = this.buildTitle(routerState); + + const projectName = this.localizationService.instant({ + key: '::AppName', + defaultValue: 'MyProjectName', + }); if (!title) { - this.title.setTitle(this.projectName()); - return; + return this.title.setTitle(projectName); + } + + let localizedText = this.localizationService.instant({ key: title, defaultValue: title }); + if (!this.disableProjectName) { + localizedText += ` | ${projectName}`; } - const localizedTitle = this.localizationService.instant({ key: title, defaultValue: title }); - this.title.setTitle(`${localizedTitle} | ${this.projectName()}`); + this.title.setTitle(localizedText); } } diff --git a/npm/ng-packs/packages/core/src/lib/tokens/index.ts b/npm/ng-packs/packages/core/src/lib/tokens/index.ts index 7d0422ad7d..3e5cecd9ca 100644 --- a/npm/ng-packs/packages/core/src/lib/tokens/index.ts +++ b/npm/ng-packs/packages/core/src/lib/tokens/index.ts @@ -14,4 +14,5 @@ export * from './check-authentication-state'; export * from './http-context.token'; export * from './others-group.token'; export * from './tenant-not-found-by-name'; -export * from './compare-func.token' +export * from './compare-func.token'; +export * from './title-strategy-disable-project-name.token'; diff --git a/npm/ng-packs/packages/core/src/lib/tokens/title-strategy-disable-project-name.token.ts b/npm/ng-packs/packages/core/src/lib/tokens/title-strategy-disable-project-name.token.ts new file mode 100644 index 0000000000..afbee19528 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/tokens/title-strategy-disable-project-name.token.ts @@ -0,0 +1,3 @@ +import { InjectionToken } from '@angular/core'; + +export const DISABLE_PROJECT_NAME = new InjectionToken<boolean>('DISABLE_APP_NAME'); diff --git a/templates/module/angular/projects/dev-app/src/index.html b/templates/module/angular/projects/dev-app/src/index.html index 067936da71..88a791e8e4 100644 --- a/templates/module/angular/projects/dev-app/src/index.html +++ b/templates/module/angular/projects/dev-app/src/index.html @@ -1,13 +1,13 @@ -<!doctype html> +<!DOCTYPE html> <html lang="en"> -<head> - <meta charset="utf-8"> - <title>DevApp - - - - - - - + + + MyProjectName + + + + + + +