diff --git a/docs/en/UI/Angular/Modifying-the-Menu.md b/docs/en/UI/Angular/Modifying-the-Menu.md index 450a5aecd1..76298e1674 100644 --- a/docs/en/UI/Angular/Modifying-the-Menu.md +++ b/docs/en/UI/Angular/Modifying-the-Menu.md @@ -25,9 +25,99 @@ export const environment = { ## How to Add a Navigation Element +### Via `RoutesService` + +You can add routes to the menu by calling the `add` method of `RoutesService`. It is a singleton service, i.e. provided in root, so you can inject and use it immediately. + +```js +import { RoutesService, eLayoutType } from '@abp/ng.core'; +import { Component } from '@angular/core'; + +@Component(/* component metadata */) +export class AppComponent { + constructor(routes: RoutesService) { + routes.add([ + { + path: '/your-path', + name: 'Your navigation', + order: 101, + iconClass: 'fas fa-question-circle', + requiredPolicy: 'permission key here', + layout: eLayoutType.application, + }, + { + path: '/your-path/child', + name: 'Your child navigation', + parentName: 'Your navigation', + order: 1, + requiredPolicy: 'permission key here', + }, + ]); + } +} +``` + +An alternative and probably cleaner way is to use a route provider. First create a provider: + +```js +// route.provider.ts +import { RoutesService, eLayoutType } from '@abp/ng.core'; +import { APP_INITIALIZER } from '@angular/core'; + +export const APP_ROUTE_PROVIDER = [ + { provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true }, +]; + +function configureRoutes(routes: RoutesService) { + return () => { + routes.add([ + { + path: '/your-path', + name: 'Your navigation', + requiredPolicy: 'permission key here', + order: 101, + iconClass: 'fas fa-question-circle', + layout: eLayoutType.application, + }, + { + path: '/your-path/child', + name: 'Your child navigation', + parentName: 'Your navigation', + requiredPolicy: 'permission key here', + order: 1, + }, + ]); + }; +} +``` + +...and then in app.module.ts... + +```js +import { NgModule } from '@angular/core'; +import { APP_ROUTE_PROVIDER } from './route.provider'; + +@NgModule({ + providers: [APP_ROUTE_PROVIDER], + // imports, declarations, and bootstrap +}) +export class AppModule {} +``` + +Here is what every property works as: + +- `path` is the absolute path of the navigation element. +- `name` is the label of the navigation element. A localization key or a localization object can be passed. +- `parentName` is a reference to the `name` of the parent route in the menu and is used for creating multi-level menu items. +- `requiredPolicy` is the permission key to access the page. See the [Permission Management document](./Permission-Management.md) +- `order` is the order of the navigation element. "Administration" has an order of `100`, so keep that in mind when ordering top level menu items. +- `iconClass` is the class of the `i` tag, which is placed to the left of the navigation label. +- `layout` defines in which layout the route will be loaded. (default: `eLayoutType.empty`) +- `invisible` makes the item invisible in the menu. (default: `false`) + ### Via `routes` Property in `AppRoutingModule` -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 `ConfigState`. `ApplicationLayoutComponent` gets routes from store and displays them on the menu. +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 add the `routes` property like below: @@ -37,7 +127,7 @@ You can add the `routes` property like below: data: { routes: { name: 'Your navigation', - order: 3, + order: 101, iconClass: 'fas fa-question-circle', requiredPolicy: 'permission key here', children: [ @@ -48,99 +138,77 @@ You can add the `routes` property like below: requiredPolicy: 'permission key here', }, ], - } as ABP.Route, // can be imported from @abp/ng.core - } + }, + }, } ``` -- `name` is the label of the navigation element. A localization key or a localization object can be passed. -- `order` is the order of the navigation element. -- `iconClass` is the class of the `i` tag, which is placed to the left of the navigation label. -- `requiredPolicy` is the permission key to access the page. See the [Permission Management document](./Permission-Management.md) -- `children` is an array and is used for declaring child navigation elements. The child navigation element will be placed as a child route which will be available at `'/your-path/child'` based on the given `path` property. - -After adding the `routes` property as described above, the navigation menu looks like this: - -![navigation-menu-via-app-routing](./images/navigation-menu-via-app-routing.png) - -## Via ConfigState - -The `dispatchAddRoute` method of `ConfigStateService` adds a new navigation element to the menu. +Alternatively, you can do this: ```js -// this.config is instance of ConfigStateService - -const newRoute: ABP.Route = { - name: 'My New Page', - iconClass: 'fa fa-dashboard', - path: 'page', - invisible: false, - order: 2, - requiredPolicy: 'MyProjectName.MyNewPage', -} as Omit; - -this.config.dispatchAddRoute(newRoute); -// returns a state stream which emits after dispatch action is complete -``` - -The `newRoute` will be placed as at root level, i.e. without any parent routes, and its url will be stored as `'/path'`. - -If you want **to add a child route, you can do this:** - -```js -// this.config is instance of ConfigStateService -// eIdentityRouteNames enum can be imported from @abp/ng.identity - -const newRoute: ABP.Route = { - parentName: eIdentityRouteNames.IdentityManagement, - name: 'My New Page', - iconClass: 'fa fa-dashboard', - path: 'page', - invisible: false, - order: 3, - requiredPolicy: 'MyProjectName.MyNewPage' -} as Omit; - -this.config.dispatchAddRoute(newRoute); -// returns a state stream which emits after dispatch action is complete +{ + path: 'your-path', + data: { + routes: [ + { + path: '/your-path', + name: 'Your navigation', + order: 101, + iconClass: 'fas fa-question-circle', + requiredPolicy: 'permission key here', + }, + { + path: '/your-path/child', + name: 'Your child navigation', + parentName: 'Your navigation', + order: 1, + requiredPolicy: 'permission key here', + }, + ] as ABP.Route[], // can be imported from @abp/ng.core + }, +} ``` -The `newRoute` will then be placed as a child of the parent route named `eIdentityRouteNames.IdentityManagement` and its url will be set as `'/identity/page'`. +The advantage of the second method is that you are not bound to the parent/child structure and use any paths you like. -The new route will be added like below: +After adding the `routes` property as described above, the navigation menu looks like this: -![navigation-menu-via-config-state](./images/navigation-menu-via-config-state.png) +![navigation-menu-via-app-routing](./images/navigation-menu-via-app-routing.png) -## How to Patch a Navigation Element +## How to Patch or Remove a Navigation Element -The `dispatchPatchRouteByName` method finds a route by its name and replaces its configuration in the store with the new configuration passed as the second parameter. +The `patch` method of `RoutesService` finds a route by its name and replaces its configuration with the new configuration passed as the second parameter. Similarly, `remove` method finds a route and removes it along with its children. ```js -// this.config is instance of ConfigStateService -// eIdentityRouteNames enum can be imported from @abp/ng.identity +// this.routes is instance of RoutesService +// eThemeSharedRouteNames enum can be imported from @abp/ng.theme.shared + +const dashboardRouteConfig: ABP.Route = { + path: '/dashboard', + name: '::Menu:Dashboard', + parentName: '::Menu:Home', + order: 1, + layout: eLayoutType.application, +}; -const newRouteConfig: Partial = { +const newHomeRouteConfig: Partial = { iconClass: 'fas fa-home', - parentName: eIdentityRouteNames.Administration, + parentName: eThemeSharedRouteNames.Administration, order: 0, - children: [ - { - name: 'Dashboard', - path: 'dashboard', - }, - ], }; -this.config.dispatchPatchRouteByName('::Menu:Home', newRouteConfig); -// returns a state stream which emits after dispatch action is complete +this.routes.add([dashboardRouteConfig]); +this.routes.patch('::Menu:Home', newHomeRouteConfig); +this.routes.remove(['Your navigation']); ``` -* Moved the _Home_ navigation under the _Administration_ dropdown based on given `parentName`. -* Added an icon. -* Specified the order. -* Added a child route named _Dashboard_. +- Moved the _Home_ navigation under the _Administration_ dropdown based on given `parentName`. +- Added an icon to _Home_. +- Specified the order and made _Home_ the first item in list. +- Added a route named _Dashboard_ as a child of _Home_. +- Removed _Your navigation_ along with its child route. -After the patch above, navigation elements looks like below: +After the operations above, the new menu looks like below: ![navigation-menu-after-patching](./images/navigation-menu-after-patching.png)