重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
umbraco-picker-data-source by umbraco/umbraco-cms-backoffice-skills
npx skills add https://github.com/umbraco/umbraco-cms-backoffice-skills --skill umbraco-picker-data-source选择器数据源为基于选择器的属性编辑器提供数据。它允许您创建自定义数据源,为内容选择器提供项目,定义如何以树形或集合格式获取、搜索和显示项目。这对于创建从自定义实体、外部 API 或现有内容的过滤子集中进行选择的选择器非常有用。
在实现之前,请始终获取最新文档:
Umbraco 源代码包含工作示例:
位置 : /Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/picker-data-source/
此示例演示了多种选择器数据源实现:
仓库模式 : 用于数据获取模式
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
umbraco-repository-pattern树 : 用于基于树的选择器数据源
umbraco-treeimport { UMB_PICKER_DATA_SOURCE_TYPE } from '@umbraco-cms/backoffice/picker-data-source';
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'propertyEditorDataSource',
dataSourceType: UMB_PICKER_DATA_SOURCE_TYPE,
alias: 'My.PropertyEditorDataSource.CustomPicker',
name: 'Custom Picker Data Source',
api: () => import('./my-picker-data-source.js'),
meta: {
label: 'Custom Items',
icon: 'icon-list',
description: 'Pick from custom items',
},
},
];
适用于具有父子关系的分层数据:
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type {
UmbPickerSearchableDataSource,
UmbPickerTreeDataSource,
} from '@umbraco-cms/backoffice/picker-data-source';
import type { UmbSearchRequestArgs, UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search';
import type { UmbTreeChildrenOfRequestArgs, UmbTreeItemModel } from '@umbraco-cms/backoffice/tree';
export class MyPickerTreeDataSource
extends UmbControllerBase
implements UmbPickerTreeDataSource, UmbPickerSearchableDataSource
{
// 过滤函数,用于确定哪些项目可以被选择
treePickableFilter: (treeItem: UmbTreeItemModel) => boolean = (treeItem) =>
!!treeItem.unique && treeItem.entityType === 'my-entity';
searchPickableFilter: (searchItem: UmbSearchResultItemModel) => boolean = (searchItem) =>
!!searchItem.unique && searchItem.entityType === 'my-entity';
// 返回根节点(所有项目的容器)
async requestTreeRoot() {
return {
data: {
unique: null,
name: 'My Items',
icon: 'icon-folder',
hasChildren: true,
entityType: 'my-entity-root',
isFolder: true,
},
};
}
// 返回根级别的项目
async requestTreeRootItems() {
const rootItems = myItems.filter((item) => item.parent.unique === null);
return {
data: {
items: rootItems,
total: rootItems.length,
},
};
}
// 返回特定项目的子项
async requestTreeItemsOf(args: UmbTreeChildrenOfRequestArgs) {
const items = myItems.filter(
(item) =>
item.parent.entityType === args.parent.entityType &&
item.parent.unique === args.parent.unique
);
return {
data: {
items: items,
total: items.length,
},
};
}
// 返回用于面包屑导航的祖先节点
async requestTreeItemAncestors() {
return { data: [] };
}
// 根据唯一 ID 返回特定项目
async requestItems(uniques: Array<string>) {
const items = myItems.filter((x) => uniques.includes(x.unique));
return { data: items };
}
// 通过查询字符串搜索项目
async search(args: UmbSearchRequestArgs) {
const result = myItems.filter((item) =>
item.name.toLowerCase().includes(args.query.toLowerCase())
);
return {
data: {
items: result,
total: result.length,
},
};
}
}
export { MyPickerTreeDataSource as api };
// 示例数据
const myItems: Array<UmbTreeItemModel> = [
{
unique: '1',
entityType: 'my-entity',
name: 'Item 1',
icon: 'icon-document',
parent: { unique: null, entityType: 'my-entity-root' },
isFolder: false,
hasChildren: false,
},
{
unique: '2',
entityType: 'my-entity',
name: 'Item 2',
icon: 'icon-document',
parent: { unique: null, entityType: 'my-entity-root' },
isFolder: false,
hasChildren: false,
},
];
适用于没有层次结构的扁平列表:
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbPickerCollectionDataSource } from '@umbraco-cms/backoffice/picker-data-source';
import type { UmbCollectionItemModel } from '@umbraco-cms/backoffice/collection';
export class MyPickerCollectionDataSource
extends UmbControllerBase
implements UmbPickerCollectionDataSource
{
async requestCollection() {
const items: UmbCollectionItemModel[] = [
{ unique: '1', entityType: 'my-entity', name: 'Item 1', icon: 'icon-document' },
{ unique: '2', entityType: 'my-entity', name: 'Item 2', icon: 'icon-document' },
{ unique: '3', entityType: 'my-entity', name: 'Item 3', icon: 'icon-document' },
];
return {
data: {
items,
total: items.length,
},
};
}
async requestItems(uniques: Array<string>) {
// 根据唯一 ID 返回特定项目
const allItems = await this.requestCollection();
const items = allItems.data.items.filter((x) => uniques.includes(x.unique));
return { data: items };
}
}
export { MyPickerCollectionDataSource as api };
向选择器数据源添加设置:
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'propertyEditorDataSource',
dataSourceType: UMB_PICKER_DATA_SOURCE_TYPE,
alias: 'My.PropertyEditorDataSource.ConfigurablePicker',
name: 'Configurable Picker Data Source',
api: () => import('./my-configurable-picker-data-source.js'),
meta: {
label: 'Configurable Items',
icon: 'icon-settings',
description: 'Pick items with configuration options',
settings: {
properties: [
{
alias: 'startNode',
label: 'Start Node',
description: 'Select where to start picking from',
propertyEditorUiAlias: 'Umb.PropertyEditorUi.ContentPicker.Source',
},
{
alias: 'filter',
label: 'Filter Types',
description: 'Select which types can be picked',
propertyEditorUiAlias: 'Umb.PropertyEditorUi.ContentPicker.SourceType',
},
],
},
},
},
];
interface UmbPickerTreeDataSource {
treePickableFilter?: (treeItem: UmbTreeItemModel) => boolean;
requestTreeRoot(): Promise<{ data: UmbTreeItemModel }>;
requestTreeRootItems(): Promise<{ data: { items: UmbTreeItemModel[]; total: number } }>;
requestTreeItemsOf(args: UmbTreeChildrenOfRequestArgs): Promise<{ data: { items: UmbTreeItemModel[]; total: number } }>;
requestTreeItemAncestors(): Promise<{ data: UmbTreeItemModel[] }>;
requestItems(uniques: string[]): Promise<{ data: UmbTreeItemModel[] }>;
}
interface UmbPickerSearchableDataSource {
searchPickableFilter?: (searchItem: UmbSearchResultItemModel) => boolean;
search(args: UmbSearchRequestArgs): Promise<{ data: { items: UmbSearchResultItemModel[]; total: number } }>;
}
interface UmbPickerCollectionDataSource {
requestCollection(): Promise<{ data: { items: UmbCollectionItemModel[]; total: number } }>;
requestItems(uniques: string[]): Promise<{ data: UmbCollectionItemModel[] }>;
}
| 概念 | 描述 |
|---|---|
dataSourceType | 对于选择器数据源,必须是 UMB_PICKER_DATA_SOURCE_TYPE |
treePickableFilter | 用于确定哪些树形项目可以被选择的函数 |
searchPickableFilter | 用于确定哪些搜索结果可以被选择的函数 |
requestItems | 根据唯一 ID 返回项目(用于显示选中的值) |
entityType | 标识实体类型(用于过滤和路由) |
requestItems 返回与树形/集合相同的格式就是这样!请始终获取最新文档,保持示例简洁,生成完整可用的代码。
每周安装量
70
仓库
GitHub 星标数
14
首次出现
2026年2月4日
安全审计
安装于
github-copilot51
cursor24
opencode22
codex22
gemini-cli20
amp20
A Picker Data Source provides data for picker-based property editors. It allows you to create custom data sources that supply items for content pickers, defining how items are fetched, searched, and displayed in a tree or collection format. This is useful for creating pickers that select from custom entities, external APIs, or filtered subsets of existing content.
Always fetch the latest docs before implementing:
The Umbraco source includes working examples:
Location : /Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/picker-data-source/
This example demonstrates multiple picker data source implementations:
Repository Pattern : For data fetching patterns
umbraco-repository-patternTree : For tree-based picker data sources
umbraco-treeimport { UMB_PICKER_DATA_SOURCE_TYPE } from '@umbraco-cms/backoffice/picker-data-source';
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'propertyEditorDataSource',
dataSourceType: UMB_PICKER_DATA_SOURCE_TYPE,
alias: 'My.PropertyEditorDataSource.CustomPicker',
name: 'Custom Picker Data Source',
api: () => import('./my-picker-data-source.js'),
meta: {
label: 'Custom Items',
icon: 'icon-list',
description: 'Pick from custom items',
},
},
];
For hierarchical data with parent-child relationships:
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type {
UmbPickerSearchableDataSource,
UmbPickerTreeDataSource,
} from '@umbraco-cms/backoffice/picker-data-source';
import type { UmbSearchRequestArgs, UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search';
import type { UmbTreeChildrenOfRequestArgs, UmbTreeItemModel } from '@umbraco-cms/backoffice/tree';
export class MyPickerTreeDataSource
extends UmbControllerBase
implements UmbPickerTreeDataSource, UmbPickerSearchableDataSource
{
// Filter function to determine which items can be picked
treePickableFilter: (treeItem: UmbTreeItemModel) => boolean = (treeItem) =>
!!treeItem.unique && treeItem.entityType === 'my-entity';
searchPickableFilter: (searchItem: UmbSearchResultItemModel) => boolean = (searchItem) =>
!!searchItem.unique && searchItem.entityType === 'my-entity';
// Return the root node (container for all items)
async requestTreeRoot() {
return {
data: {
unique: null,
name: 'My Items',
icon: 'icon-folder',
hasChildren: true,
entityType: 'my-entity-root',
isFolder: true,
},
};
}
// Return items at the root level
async requestTreeRootItems() {
const rootItems = myItems.filter((item) => item.parent.unique === null);
return {
data: {
items: rootItems,
total: rootItems.length,
},
};
}
// Return children of a specific item
async requestTreeItemsOf(args: UmbTreeChildrenOfRequestArgs) {
const items = myItems.filter(
(item) =>
item.parent.entityType === args.parent.entityType &&
item.parent.unique === args.parent.unique
);
return {
data: {
items: items,
total: items.length,
},
};
}
// Return ancestors for breadcrumb navigation
async requestTreeItemAncestors() {
return { data: [] };
}
// Return specific items by their unique IDs
async requestItems(uniques: Array<string>) {
const items = myItems.filter((x) => uniques.includes(x.unique));
return { data: items };
}
// Search items by query string
async search(args: UmbSearchRequestArgs) {
const result = myItems.filter((item) =>
item.name.toLowerCase().includes(args.query.toLowerCase())
);
return {
data: {
items: result,
total: result.length,
},
};
}
}
export { MyPickerTreeDataSource as api };
// Sample data
const myItems: Array<UmbTreeItemModel> = [
{
unique: '1',
entityType: 'my-entity',
name: 'Item 1',
icon: 'icon-document',
parent: { unique: null, entityType: 'my-entity-root' },
isFolder: false,
hasChildren: false,
},
{
unique: '2',
entityType: 'my-entity',
name: 'Item 2',
icon: 'icon-document',
parent: { unique: null, entityType: 'my-entity-root' },
isFolder: false,
hasChildren: false,
},
];
For flat lists without hierarchy:
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbPickerCollectionDataSource } from '@umbraco-cms/backoffice/picker-data-source';
import type { UmbCollectionItemModel } from '@umbraco-cms/backoffice/collection';
export class MyPickerCollectionDataSource
extends UmbControllerBase
implements UmbPickerCollectionDataSource
{
async requestCollection() {
const items: UmbCollectionItemModel[] = [
{ unique: '1', entityType: 'my-entity', name: 'Item 1', icon: 'icon-document' },
{ unique: '2', entityType: 'my-entity', name: 'Item 2', icon: 'icon-document' },
{ unique: '3', entityType: 'my-entity', name: 'Item 3', icon: 'icon-document' },
];
return {
data: {
items,
total: items.length,
},
};
}
async requestItems(uniques: Array<string>) {
// Return specific items by unique IDs
const allItems = await this.requestCollection();
const items = allItems.data.items.filter((x) => uniques.includes(x.unique));
return { data: items };
}
}
export { MyPickerCollectionDataSource as api };
Add settings to your picker data source:
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'propertyEditorDataSource',
dataSourceType: UMB_PICKER_DATA_SOURCE_TYPE,
alias: 'My.PropertyEditorDataSource.ConfigurablePicker',
name: 'Configurable Picker Data Source',
api: () => import('./my-configurable-picker-data-source.js'),
meta: {
label: 'Configurable Items',
icon: 'icon-settings',
description: 'Pick items with configuration options',
settings: {
properties: [
{
alias: 'startNode',
label: 'Start Node',
description: 'Select where to start picking from',
propertyEditorUiAlias: 'Umb.PropertyEditorUi.ContentPicker.Source',
},
{
alias: 'filter',
label: 'Filter Types',
description: 'Select which types can be picked',
propertyEditorUiAlias: 'Umb.PropertyEditorUi.ContentPicker.SourceType',
},
],
},
},
},
];
interface UmbPickerTreeDataSource {
treePickableFilter?: (treeItem: UmbTreeItemModel) => boolean;
requestTreeRoot(): Promise<{ data: UmbTreeItemModel }>;
requestTreeRootItems(): Promise<{ data: { items: UmbTreeItemModel[]; total: number } }>;
requestTreeItemsOf(args: UmbTreeChildrenOfRequestArgs): Promise<{ data: { items: UmbTreeItemModel[]; total: number } }>;
requestTreeItemAncestors(): Promise<{ data: UmbTreeItemModel[] }>;
requestItems(uniques: string[]): Promise<{ data: UmbTreeItemModel[] }>;
}
interface UmbPickerSearchableDataSource {
searchPickableFilter?: (searchItem: UmbSearchResultItemModel) => boolean;
search(args: UmbSearchRequestArgs): Promise<{ data: { items: UmbSearchResultItemModel[]; total: number } }>;
}
interface UmbPickerCollectionDataSource {
requestCollection(): Promise<{ data: { items: UmbCollectionItemModel[]; total: number } }>;
requestItems(uniques: string[]): Promise<{ data: UmbCollectionItemModel[] }>;
}
| Concept | Description |
|---|---|
dataSourceType | Must be UMB_PICKER_DATA_SOURCE_TYPE for picker data sources |
treePickableFilter | Function to determine which tree items can be selected |
searchPickableFilter | Function to determine which search results can be selected |
requestItems | Returns items by their unique IDs (for displaying selected values) |
entityType | Identifies the type of entity (used for filtering and routing) |
requestItems returns the same format as tree/collectionThat's it! Always fetch fresh docs, keep examples minimal, generate complete working code.
Weekly Installs
70
Repository
GitHub Stars
14
First Seen
Feb 4, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
github-copilot51
cursor24
opencode22
codex22
gemini-cli20
amp20
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
122,000 周安装