Angular UI 页面工具栏扩展
简介
页面工具栏扩展系统允许您向页面的工具栏添加新操作。下图在用户管理页面添加了一个"点击我"操作:
您可以通过编写自定义代码来执行任何操作(打开模态框、发起HTTP API调用、重定向到其他页面等)。您还可以在代码中访问页面数据(主记录,通常是实体列表)。此外,您可以传入自定义组件来替代默认按钮。
如何向页面工具栏添加操作
在本示例中,我们将在身份模块的用户管理页面添加一个"点击我!"操作,并将所有用户的userName记录到控制台。
步骤 1. 创建工具栏操作贡献者
以下代码准备了一个名为identityToolbarActionContributors的常量,可供导入并在您的根应用程序配置中使用:
// src/app/toolbar-action-contributors.ts
import {
eIdentityComponents,
IdentityToolbarActionContributors
} from '@abp/ng.identity';
import { IdentityUserDto } from '@abp/ng.identity/proxy';
import { ToolbarAction, ToolbarActionList } from '@abp/ng.components/extensible';
const logUserNames = new ToolbarAction<IdentityUserDto[]>({
text: '点击我!',
action: data => {
// 用您的自定义代码替换此日志记录
data.record.forEach(user => console.log(user.userName));
},
// 所有选项请参见API部分中的ToolbarActionOptions
});
export function logUserNamesContributor(actionList: ToolbarActionList<IdentityUserDto[]>) {
actionList.addHead(logUserNames);
}
export const identityToolbarActionContributors: IdentityToolbarActionContributors = {
// 枚举表示要添加贡献者的页面
[eIdentityComponents.Users]: [
logUserNamesContributor,
// 您可以在此处添加更多贡献者
],
};
操作列表(方便地命名为actionList)是一个双向链表。这就是我们使用addHead方法的原因,它将给定值添加到列表的开头。您可以在此处找到所有可用方法。
步骤 2. 导入并使用工具栏操作贡献者
在您的路由配置中导入identityToolbarActionContributors,并将其传递给identity路由的静态createRoutes方法,如下所示:
// src/app/app.routes.ts
// 其他导入
import { identityToolbarActionContributors } from './toolbar-action-contributors';
export const APP_ROUTES: Routes = [
// 其他路由
{
path: 'identity',
loadChildren: () =>
import('@abp/ng.identity').then(c =>
c.createRoutes({
toolbarActionContributors: identityToolbarActionContributors,
})
),
},
// 其他路由
];
这样,logUserNames工具栏操作将作为identity包的users页面(UsersComponent)中页面工具栏上的第一个操作添加。
如何向页面工具栏添加自定义组件
在本示例中,我们将添加一个自定义的"点击我!"按钮,并将身份模块的用户管理页面中所有用户的userName记录到控制台。
步骤 1. 创建自定义组件
我们需要先创建一个组件,然后才能将其传递给工具栏操作贡献者:
// src/app/click-me-button.component.ts
import { Component, Inject } from '@angular/core';
import { IdentityUserDto } from '@abp/ng.identity/proxy';
import { ActionData, EXTENSIONS_ACTION_DATA } from '@abp/ng.components/extensible';
@Component({
selector: 'app-click-me-button',
template: `<button class="btn btn-warning" (click)="handleClick()">点击我!</button>`,
})
export class ClickMeButtonComponent {
constructor(
@Inject(EXTENSIONS_ACTION_DATA)
private data: ActionData<IdentityUserDto[]>
) {}
handleClick() {
this.data.record.forEach(user => console.log(user.userName));
}
}
这里,EXTENSIONS_ACTION_DATA令牌为我们提供了来自页面工具栏的上下文。因此,我们能够通过record访问页面数据,它是一个用户数组,即IdentityUserDto[]。
我们还可以从 @abp/ng.components/extensible 包导入
EXTENSIONS_ACTION_CALLBACK,它是一个高阶函数,调用时会触发预定义的action。它将ActionData作为第一个参数传递,因此您无需显式传递它。换句话说,EXTENSIONS_ACTION_CALLBACK可以在没有任何参数的情况下调用,并且不会失败。
步骤 2. 创建工具栏操作贡献者
以下代码准备了一个名为identityToolbarActionContributors的常量,可供导入并在您的根应用程序配置中使用。当使用ToolbarComponent而不是ToolbarAction时,我们可以传入一个组件:
// src/app/toolbar-action-contributors.ts
import {
eIdentityComponents,
IdentityToolbarActionContributors
} from '@abp/ng.identity';
import { IdentityUserDto } from '@abp/ng.identity/proxy';
import { ToolbarActionList, ToolbarComponent } from '@abp/ng.components/extensible';
import { ClickMeButtonComponent } from './click-me-button.component';
const logUserNames = new ToolbarComponent<IdentityUserDto[]>({
component: ClickMeButtonComponent,
// 所有选项请参见API部分中的ToolbarActionOptions
});
export function logUserNamesContributor(actionList: ToolbarActionList<IdentityUserDto[]>) {
actionList.addHead(logUserNames);
}
export const identityToolbarActionContributors: IdentityToolbarActionContributors = {
// 枚举表示要添加贡献者的页面
[eIdentityComponents.Users]: [
logUserNamesContributor,
// 您可以在此处添加更多贡献者
],
};
操作列表(方便地命名为actionList)是一个双向链表。这就是我们使用addHead方法的原因,它将给定值添加到列表的开头。您可以在此处找到所有可用方法。
步骤 3. 导入并使用工具栏操作贡献者
在您的路由配置中导入identityToolbarActionContributors,并将其传递给identity路由的静态createRoutes方法,如下所示。
// src/app/app.routes.ts
// 其他导入
import { identityToolbarActionContributors } from './toolbar-action-contributors';
export const APP_ROUTES: Routes = [
// 其他路由
{
path: 'identity',
loadChildren: () =>
import('@abp/ng.identity').then(c =>
c.createRoutes({
toolbarActionContributors: identityToolbarActionContributors,
})
),
},
// 其他路由
];
这样,logUserNames工具栏操作将作为identity包的users页面(UsersComponent)中页面工具栏上的第一个操作添加,并且将由自定义按钮(即ClickMeButtonComponent)触发。请注意,组件投射不仅限于按钮,您可以使用其他UI组件。
如何放置自定义模态框并通过工具栏操作触发它
请查看实体操作扩展文档中的相同主题,并将实体操作替换为工具栏操作。
API
ActionData<R = any>
ActionData是传递给ToolbarAction中所有回调或谓词的参数类型。
它具有以下属性:
record 是页面数据,页面上的主记录,通常是实体列表(例如用户列表)。
{ text: '点击我!', action: data => { data.record.forEach(user => { console.log(user.userName); }); }, }getInjected 等同于Injector.get。您可以使用它来获取
PageToolbarComponent的注入依赖项,包括但不限于其父组件。{ text: '点击我!', action: data => { const restService = data.getInjected(RestService); // 在此处使用restService的公共属性和方法 }, visible: data => { const usersComponent = data.getInjected(UsersComponent); // 在此处使用usersComponent的公共属性和方法 }, }
ActionCallback<T, R = any>
ActionCallback是可以作为action参数传递给ToolbarAction的回调函数类型。操作回调接收单个参数ActionData。返回类型可以是任何类型,包括void。以下是简化表示:
type ActionCallback<T, R = any> = (data?: ActionData<T>) => R;
ActionPredicate<T>
ActionPredicate是可以作为visible参数传递给ToolbarAction的谓词函数类型。操作谓词接收单个参数ActionData。返回类型必须为boolean。以下是简化表示:
type ActionPredicate<T> = (data?: ActionData<T>) => boolean;
ToolbarActionOptions<R = any>
ToolbarActionOptions是定义创建工具栏操作时必须传递的必需和可选属性的类型。
其类型定义如下:
type ToolbarActionOptions<R = any> = {
action: ActionCallback<R>,
text: string,
icon?: string,
permission?: string,
visible?: ActionPredicate<R>,
};
如您所见,传递action和text足以创建工具栏操作。以下是每个属性的作用:
- action 是点击工具栏操作时调用的回调函数。(必需)
- text 是将被本地化的按钮文本。(必需)
- icon 是定义放置在文本前的图标的类。(默认值:
'') - permission 是权限上下文,用于决定是否应向用户显示此工具栏操作。(默认值:
undefined) - visible 是一个谓词,用于决定页面工具栏是否应具有此操作。(默认值:
() => true)
您可以在下方找到完整示例。
ToolbarAction<R = any>
ToolbarAction是定义工具栏操作的类。它接收一个ToolbarActionOptions并为属性设置默认值,创建一个可以传递给工具栏贡献者的工具栏操作。
const options: ToolbarActionOptions<IdentityUserDto[]> = {
action: data => {
const service = data.getInjected(MyCustomIdentityService);
const lockedUsers = data.record.filter(user => user.isLockedOut);
service.unlockAll(lockedUsers);
},
text: 'MyProjectName::解锁全部',
icon: 'fa fa-unlock',
permission: 'AbpIdentity.Users.Update',
visible: data => data.record.some(user => user.isLockedOut),
};
const action = new ToolbarAction(options);
它还有两个静态方法来创建其实例:
ToolbarAction.create<R = any>(options: ToolbarActionOptions<R>) 用于创建
ToolbarAction的实例。const action = ToolbarAction.create(options);ToolbarAction.createMany<R = any>(options: ToolbarActionOptions<R>[]) 用于使用给定的
ToolbarActionOptions数组创建多个ToolbarAction实例。
ToolbarComponentOptions<R = any>
ToolbarComponentOptions是定义创建工具栏组件时必须传递的必需和可选属性的类型。
其类型定义如下:
type ToolbarComponentOptions<R = any> = {
component: Type<any>,
action?: ActionCallback<R>,
permission?: string,
visible?: ActionPredicate<R>,
};
如您所见,传递action和text足以创建工具栏操作。以下是每个属性的作用:
- component 是要被投射的组件的构造函数。(必需)
- action 是一个预定义的回调,您可以在组件中通过
EXTENSIONS_ACTION_CALLBACK令牌访问并触发它。(可选) - permission 是权限上下文,用于决定是否应向用户显示此工具栏操作。(默认值:
undefined) - visible 是一个谓词,用于决定页面工具栏是否应具有此操作。(默认值:
() => true)
您可以在下方找到完整示例。
ToolbarComponent<R = any>
ToolbarComponent是定义投射自定义组件的工具栏操作的类。它接收一个ToolbarComponentOptions并为属性设置默认值,创建一个可以传递给工具栏贡献者的工具栏操作。
const options: ToolbarComponentOptions<IdentityUserDto[]> = {
component: UnlockAllButton,
action: data => {
const service = data.getInjected(MyCustomIdentityService);
const lockedUsers = data.record.filter(user => user.isLockedOut);
service.unlockAll(lockedUsers);
},
permission: 'AbpIdentity.Users.Update',
visible: data => data.record.some(user => user.isLockedOut),
};
const action = new ToolbarComponent(options);
它还有两个静态方法来创建其实例:
ToolbarComponent.create<R = any>(options: ToolbarComponentOptions<R>) 用于创建
ToolbarComponent的实例。const action = ToolbarComponent.create(options);ToolbarComponent.createMany<R = any>(options: ToolbarComponentOptions<R>[]) 用于使用给定的
ToolbarComponentOptions数组创建多个ToolbarComponent实例。const actions = ToolbarComponent.createMany(optionsArray);
ToolbarActionList<R = any>
ToolbarActionList是作为第一个参数(名为actionList)传递给每个操作贡献者回调的操作列表。它是一个双向链表。您可以在此处找到所有可用方法。
列表中的项将按照链表顺序显示,即从头到尾。如果您想重新排序,只需执行以下操作:
export function reorderUserContributors(
actionList: ToolbarActionList<IdentityUserDto[]>,
) {
// 删除"新建用户"按钮
const newUserActionNode = actionList.dropByValue(
'AbpIdentity::NewUser',
(action, text) => action['text'] === text,
);
// 将其添加回列表头部
actionList.addHead(newUserActionNode.value);
}
export const identityEntityActionContributors = {
[eIdentityComponents.Users]: [
logUserNamesContributor,
reorderUserContributors,
],
};
ToolbarActionContributorCallback<R = any>
ToolbarActionContributorCallback是您可以作为工具栏操作贡献者回调传递给包静态createRoutes方法的类型。
// exportUsersContributor 应具有 ToolbarActionContributorCallback<IdentityUserDto[]> 类型
export function exportUsersContributor(
actionList: ToolbarActionList<IdentityUserDto[]>,
) {
// 在最后一个操作之前添加exportUsers
actionList.add(exportUsers).byIndex(-1);
}
export const identityEntityActionContributors = {
[eIdentityComponents.Users]: [exportUsersContributor],
};
抠丁客


