Angular 表单库 | ng-hub-ui-forms
无障碍的 Angular 表单字段(input、textarea、滑块、select、日期选择器),在控件、组和表单级别自动显示校验错误,支持响应式表单和 CSS 变量。
API 参考
这里是 forms 的完整契约:你可以绑定、监听、投影和设置主题的一切,都集中在一处。接入你需要的部分,自定义你想要的样式——它是 standalone 的,且对 signal 友好。
输入
通过 87 个输入项精细调校 forms。像绑定任意 Angular @Input 一样绑定它们。
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
formControlName / [formControl] | string | FormControl | — | 将任意字段绑定到响应式控件。当控件被触碰且无效时自动显示错误。 |
label | string | '' | 字段标签文本。 |
labelType (hub-input, hub-select, hub-datepicker) | 'stacked' | 'floating' | 'horizontal' | 'stacked' | 标签位置。`floating` 会把标签置于控件内部,在字段获得焦点或持有值之前,由它代替占位符。 |
labelType (hub-textarea, hub-otp-input, hub-slider, hub-segmented, hub-timepicker) | 'stacked' | 'horizontal' | 'stacked' | 标签位置。这些字段没有 `floating` 变体:传入 `floating` 时,它们会渲染为堆叠式标签。 |
placeholder (hub-input, hub-select, hub-textarea, hub-datepicker) | string | '' / NgSelectConfig.placeholder (hub-select) | 占位符文本。 |
formText | string | — | 显示在控件下方的辅助文本。 |
type (hub-input) — file is deprecated | 'text' | 'number' | 'password' | 'email' | 'tel' | 'url' | 'color' | 'checkbox' | 'switch' | 'counter' | 'file' | 'text' | hub-input 的格式。 |
passwordRevealed (hub-input) | boolean | false | 密码字段可见状态的双向绑定。点击眼睛按钮会更新它;设置该值可显示或隐藏密码。 |
passwordToggle (hub-input) | boolean | true | 是否在密码字段上渲染内置的显示/隐藏切换按钮。 |
hideOnBlur (hub-input) | boolean | true | 字段失去焦点时,已显示的密码是否自动重新隐藏。 |
capsLockWarning (hub-input) | boolean | true | Caps Lock 激活时,是否在字段下方显示提示。 |
passwordStrength (hub-input) | boolean | false | 在字段下方渲染可选的 4 段强度指示器。评分逻辑可通过 provideHubForms 覆盖。 |
autocomplete (hub-input) | string | '' | 原生 autocomplete 属性,例如为密码管理器指定 current-password 或 new-password。 |
clearable (hub-input) | boolean | false | 为 true 时,字段有值后显示内置的 ✕ 按钮;点击可清空控件并发出空的搜索词。 |
debounceTime (hub-input) | number | 0 | 触发 search 事件前的防抖毫秒数(0 表示每次按键)。 |
mask (hub-input) | string | — | 文本格式的模式掩码。标记:0 = 数字,A = 字母,* = 字母或数字;其他字符为字面分隔符。例如 "0000 0000 0000 0000"。 |
unmaskValue (hub-input) | boolean | false | 设置掩码后,在表单中存储原始输入的字符(无分隔符),而非格式化后的文本。 |
range (hub-slider) | boolean | false | 双滑块范围选择器;值变为 [lower, upper] 元组。 |
options (hub-segmented) | HubSegmentedOption[] | [] | hub-segmented 中可选中的选项,按渲染顺序排列——每一项为 { value, label, disabled? }。 |
size (hub-segmented) | 'sm' | 'md' | 'lg' | 'md' | 分段控件的视觉密度:'sm'、'md'(默认)或 'lg'。 |
disabled (all fields) | boolean (two-way, model) | false | 禁用该字段。所有字段都从共享基类继承它,并且是双向的——通过响应式控件被禁用的字段会把这一变化回报出来。在 `hub-segmented` 上,各个选项还可以通过 `option.disabled` 单独退出。 |
multiple (hub-segmented) | boolean | false | 允许选择多个选项;值变为数组,选项以 aria-pressed 切换。 |
vertical (hub-segmented) | boolean | false | 将分段垂直堆叠,而非水平排列。 |
vertical (hub-select) — deprecated | boolean | false | 已弃用,且与同样已弃用的非 dropdown 格式绑定:将 buttons/checkbox/radio 选项垂直排列。请改用 `<hub-segmented [vertical]="true">`。 |
color (hub-segmented) | 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'neutral' | string | '' | 所选分段的语义强调色(primary、success 等)或任意颜色;单选模式下滑动。 |
value (hub-segmented) | unknown | unknown[] | undefined | 可双向绑定的选中值(model()):单选模式下为所选选项的值,多选模式下为所选值的数组。会发出 valueChange;通常改由 formControlName 驱动。 |
format (hub-select) — deprecated for buttons/checkbox/radio | 'dropdown' | 'buttons' | 'checkbox' | 'radio' | 'dropdown' | select 渲染相同值的方式。 |
prepend / append (hub-input, hub-select, hub-textarea, hub-datepicker, hub-timepicker) | string | string[] | '' | 任何以方框形式呈现的字段上的静态组附加内容:字符串为一个附加项,数组为一串附加项,空条目会被丢弃而不会绘制成空框。附加项与字段共用边框且不可获得焦点——若需要贴在边缘的可交互控件,请改用 [hubPrepend] / [hubAppend] 模板。两者可以同时存在,投影内容始终是其所在一侧最外层的元素。 |
items / bindLabel / bindValue / multiple (hub-select) | any[] / string / string / boolean | — | 选项、对象项的 label/value 属性名,以及多选设置。 |
groupBy (hub-select) | string | undefined | undefined | 用于将下拉选项归入选项组标题之下的属性名(点路径)。 |
searchable / clearable (hub-select) | boolean | true | 选项是否可通过键入进行筛选(searchable),以及是否可用内置的清除按钮清空所选值(clearable)。两者默认均为 true。 |
closeOnSelect (hub-select) | boolean | true | 选中条目后下拉框是否关闭。设为 false 可在 multiple 模式下挑选多个值时保持其打开。 |
fixedPlaceholder (hub-select) | boolean | false | 即使已选中值也保持占位符可见。默认为 false(选中后占位符隐藏),反转了 ng-select v23 不合常规的默认行为。 |
loading / notFoundText (hub-select) | boolean / string | false / NgSelectConfig.notFoundText | loading 在异步获取条目期间渲染下拉框的加载状态;notFoundText 则是没有条目匹配搜索词时显示的消息。 |
readonly (hub-input, hub-select, hub-textarea, hub-datepicker, hub-otp-input, hub-timepicker) | boolean | false | 为 true 时,字段显示其值但拒绝任何交互,既不带 disabled 样式,也不改变表单状态。 |
appendTo (hub-select) | string | undefined | 'body' | 下拉面板所附加到的元素的 CSS 选择器。默认为 'body',使面板得以逃离带有 overflow/transform 的祖先元素(卡片、滚动容器、模态框);传入 undefined 可将其内联渲染。 |
addTag (hub-select) | boolean | ((term: string) => any | Promise<any>) | false | 根据搜索词创建条目(dropdown 格式):true 按原样添加该词;函数则将该词映射为新条目,可同步或返回 Promise。 |
addTagText (hub-select) | string | NgSelectConfig.addTagText | 启用 addTag 时,输入过程中显示的“添加条目”行的文案。 |
minTermLength (hub-select) | number | 0 | 触发筛选(或 typeahead Subject)之前搜索词的最小长度。 |
typeahead (hub-select) | Subject<string> | undefined | undefined | 接收搜索词变化的 Subject,用于异步/服务端加载;一旦提供,客户端筛选即被关闭——请通过 items 回传结果。 |
compareWith (hub-select) | ((a: any, b: any) => boolean) | undefined | undefined | 条目与所绑定值之间的自定义相等判断(例如按 id 比较对象);省略时采用供应商内置的比较逻辑。 |
searchFn (hub-select) | ((term: string, item: any) => boolean) | undefined | undefined | 替换 `searchable` 所使用的内置匹配逻辑。它接收键入的搜索词和一个条目,并返回该条目是否匹配——因此搜索得以查看标签并未显示的字段。 |
mode (hub-datepicker) | 'single' | 'range' | 'day-time-range' | 'single' | 单个日期、自由日期范围,或某一天内的开始与结束时间。 |
granularity (hub-datepicker) | 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'day' | 每个选定时间点所携带的精度,以及用于选取它的面板:year 和 month 渲染 12 格网格,day 渲染日历,hour、minute 和 second 则在日历下方增加时间栏。它与 mode 正交:mode 决定选取几个点,granularity 决定每个点的精度。默认值为 day,输出与以往完全相同的 YYYY-MM-DD 字符串;从 hour 起,值变为完整的 ISO 8601 时间戳,携带读者的本地时间以及该日期的时区偏移。 |
valueFormat / parse (hub-datepicker) | 'iso' | 'date' | 'timestamp' | ((date) => unknown) / ((raw) => Date | null) | null | 'iso' / null | 值的两个轴。valueFormat 决定绑定控件所持有的内容:'iso'(默认)、'date' 为原生 Date、'timestamp' 为纪元毫秒,或传入函数以应对其他情况。parse 决定传入值的读取方式,覆盖对任意宽度 ISO 字符串、Date 实例和纪元毫秒的内置识别——它同样作用于 min 与 max。 |
minuteStep / secondStep / hourFormat (hub-datepicker) | number / number / '12' | '24' | undefined | 5 / 1 / undefined | 时间相关设置:minuteStep 与 secondStep 是微调按钮的步进值,hourFormat 强制使用 12 小时制或 24 小时制——未设置时由区域设置推导,并且同时作用于输入框显示与面板,因此两者绝不会相互矛盾。三者均回退到 provideHubForms 的全局配置。 |
min / max / disabledDates (hub-datepicker) | string | Date | number | null / ((date: Date) => boolean) | null | null | 可选范围与按日期禁用的谓词。范围会考虑时间而不仅是日期:只有当某一天没有任何时刻被允许时,该天才会被禁用,因此 min = 2026-09-01T14:00 仍让 9 月 1 日可点击,而由时间控件拒绝更早的时刻。接受 ISO 字符串、Date 或纪元毫秒。 |
locale / firstDayOfWeek / weekdayFormat (hub-datepicker) | string / number / 'short' | 'narrow' | 'long' | LOCALE_ID / undefined / undefined | 日历国际化:locale 是用于显示值及月份/星期名称的 BCP-47 标签(默认为应用的 LOCALE_ID,再回退到 en-US);firstDayOfWeek 设置每周的第一天(0 = 周日,1 = 周一……);weekdayFormat 决定星期表头的宽度。后两者会回退到全局的 provideHubForms 配置。 |
displayFormat / timeDisplayFormat / rangeSeparator / labels (hub-datepicker) | Intl.DateTimeFormatOptions | string | ((date) => string) / Intl.DateTimeFormatOptions / string / Partial<HubDatepickerLabels> | undefined / undefined / undefined / {} | 显示格式:displayFormat 渲染所选值,接受 Intl.DateTimeFormatOptions、形如 'dd/MM/yyyy HH:mm' 的 Angular 日期模式,或一个函数;一旦粒度携带时间,timeDisplayFormat 会叠加其上,因此日期部分仍保持 displayFormat 所指定的样子;rangeSeparator 是范围两个日期之间的文本;labels 按实例覆盖界面标签(合并于全局配置之上)。 |
clearable / showToday / closeOnSelect (hub-datepicker) | boolean | true / true / true | 行为开关:clearable 显示清除快捷按钮,showToday 显示“今天”快捷按钮,closeOnSelect 在选定日期后关闭日历(仅单选模式)。默认值:true / true / true。 |
multiple (hub-file-input) | boolean | false | 是否可以持有多个文件。会将控件值从 File 切换为 File[]。 |
accept (hub-file-input) | string | '*' | 接受的文件类型,例如 image/*,.pdf。拖放和粘贴时同样生效,而不仅限于系统对话框。 |
maxSize / minSize / maxTotalSize (hub-file-input) | number | null | null | 单个文件的最大与最小大小,以及合计最大大小(字节)。 |
maxFiles (hub-file-input) | number | null | null | 文件数量上限。仅在配合 multiple 时有意义。 |
dragDrop / paste (hub-file-input) | boolean | true | 是否可以将文件拖放到字段上,以及是否可以粘贴进来。 |
preview (hub-file-input) | 'none' | 'list' | 'grid' | 'list' | 文件的呈现方式:不呈现、列表,或缩略图网格。 |
allowDuplicates (hub-file-input) | boolean | false | 是否允许两次选择同一个文件(以名称、大小和最后修改时间为键)。 |
capture (hub-file-input) | 'user' | 'environment' | null | null | 在支持的平台上打开设备摄像头,而非文件浏览器。 |
autoUpload (hub-file-input) | boolean | true | 新接受的文件是否立即开始上传。未注册上传器时会被忽略。 |
buttonLabel / hint (hub-file-input) | string | null | null | 覆盖浏览按钮文本以及自动生成的限制提示。 |
dropText / dropSubtext (hub-file-input) | string | null | null | 按实例覆盖拖放区的两行提示文本。两者均回退到全局标签。 |
classlist (every field except hub-segmented and hub-legend) | string | '' | 应用于宿主元素的额外 CSS 类。 |
showValid (all fields) | boolean | HubFormsConfig.showValid | 有效的字段是否显示其有效状态。默认关闭,因为把每个尚未触碰的字段都涂成绿色的表单等于什么都没说;而无效状态始终会显示。 |
validFeedback (all fields) | string | null | null | 开启 `showValid` 时,字段变为有效后在其下方渲染的消息。 |
invalidFeedbackTemplateFn (all fields) | ((key: string, value: any) => string) | null | null | 仅在此字段上覆盖指定错误键对应的消息。它接收错误键及其值并返回文本——应用级的默认实现位于 `provideHubForms`。 |
min / max (hub-input) | number | undefined (two-way, model) | undefined | number 与 counter 格式的数值上下限。双向绑定,因此自行钳制取值的计数器会把该边界回报出来。 |
mode (hub-otp-input) | 'numeric' | 'alphanumeric' | 'alpha' | 'numeric' | 每个输入框接受哪些字符,以及手机会弹出哪种键盘:仅数字,或字母与数字。 |
min / max (hub-timepicker) | string (HH:MM) | '' | 字段所接受的最早与最晚时间,格式为 `HH:MM`。留空表示不设限制。 |
step (hub-timepicker) | number (seconds) | 0 | 原生步进器的粒度,以秒为单位。`0` 表示保留浏览器默认的一分钟。 |
group / groupName (form[hubForm], hub-fieldset) | AbstractControl | null / string | undefined | null / undefined | 容器所呈现错误的目标分组。可以直接给 `group` 传入一个 `AbstractControl`,或者给 `groupName` 传入外层表单中某个子控件的名称——当容器本身已经包裹了它所报告的分组时,两者都不需要。 |
errorTrigger (form[hubForm], hub-fieldset) | 'touched' | 'submit' | 'always' | 'touched' | 分组级错误何时变为可见:分组被触碰之后、仅在尝试提交之后,或立即显示。 |
formTextType (all fields) | 'bottom' | — | 辅助文字的位置。仅支持 `bottom`。 |
rows (hub-textarea) | number | — | 可见的文本行数。 |
cols (hub-textarea) | number | — | 可见的列数。设置后文本域不再拉伸至整宽。 |
maxlength (hub-textarea) | number | — | 最大字符数。同时决定原生限制与计数器。 |
counter (hub-textarea) | boolean | — | 是否在控件下方显示字符计数器。 |
autoresize (hub-textarea) | boolean | — | 文本域是否随内容自动增高。 |
length (hub-otp-input) | number | — | 验证码的单元格(字符)数量。 |
secret (hub-otp-input) | boolean | — | 像密码一样遮蔽字符。 |
separator (hub-otp-input) | string | — | 组与组之间显示的分隔符。 |
separatorEvery (hub-otp-input) | number | — | 每 N 个单元格插入一个视觉分隔符(0 表示不插入)。 |
showValue (hub-slider) | boolean | — | 是否在滑块上方显示数值气泡。 |
step (hub-input, hub-slider) | number | — | 步进值(数字或计数器输入)。 |
legend (hub-fieldset) | string | — | 图例文字。投影 `hubLegend` 模板时会被忽略。 |
required (all fields) | boolean | null (two-way, model) | null | 该字段是否为必填。在响应式绑定下,它由控件自身的校验器推导得出,因此直接内联设置只对模板驱动的字段生效;它决定必填星号与 `required` 属性。 |
required (hub-legend) | boolean | — | 是否渲染必填指示符。 |
invalid (hub-legend) | boolean | — | 是否渲染无效状态样式。 |
输出
响应 forms 的行为——有 13 个事件可供你挂接逻辑。
| 名称 | 类型 | 描述 |
|---|---|---|
valueChange | EventEmitter<value> | 每当字段值变化时触发。 |
search (hub-input) | EventEmitter<string> | 用户输入时发出的防抖输入提示词(文本类输入)。 |
rejected (hub-file-input) | EventEmitter<HubFileRejection[]> | 被声明的限制所拒绝的文件,每个都附带拒绝原因。 |
fileRemoved (hub-file-input) | EventEmitter<File> | 从选择中移除的文件。 |
uploadStateChange (hub-file-input) | EventEmitter<readonly HubFileItem[]> | 每当上传状态或进度变化时的完整条目列表。 |
submit (form[hubForm]) — the native event | SubmitEvent (native, not a custom output) | 并非自定义输出:`hubForm` 监听表单自身的 `submit` 事件,阻止默认的导航行为,将整棵控件树标记为已触碰,并翻转 submitted 状态。若需要自己的处理器,请在表单上绑定 `(submit)`。 |
disabledChange / requiredChange (all fields) · labelTypeChange / placeholderChange / minChange / maxChange / passwordRevealedChange (hub-input) · valueChange (hub-segmented) | EventEmitter<T> (the paired half of each two-way model) | 每个双向的 `model()` 输入都会发布一个与之对应的 `Change` 输出,`[(disabled)]` 之类的写法才得以工作。之所以在此列出,是因为「香蕉盒」双向绑定语法把它们隐藏了起来。 |
opened / closed / cleared / viewChange (hub-datepicker) | EventEmitter | 日历生命周期和导航事件。 |
onOpen / onClose / onClear / onSearch / onAdd / onRemove (hub-select) | EventEmitter | 下拉框生命周期以及标签/自动补全事件。 |
onFocus / onBlur (hub-select) | EventEmitter<any> | 当下拉控件获得或失去焦点时发出(dropdown 格式),转发供应商的 focus/blur 事件。 |
scroll / scrollToEnd (hub-select) | EventEmitter<{ start: number; end: number }> / EventEmitter<any> | scroll 在下拉列表滚动时发出可见的 { start, end } 窗口;scrollToEnd 在列表到达末尾时发出——这是配合 typeahead 实现无限/分页加载的挂钩。 |
enter (hub-input) | EventEmitter<number | string | boolean | File | FileList | null> | 按下 Enter 时发出当前值。 |
completed (hub-otp-input) | EventEmitter<string> | 所有单元格填满后发出完整验证码。 |
模板
打造你自己的样式——10 个模板插槽让你可以投影自定义标记。
| 名称 | 描述 | 示例 |
|---|---|---|
hubFormText | 投影丰富的辅助文本内容。 | <ng-template hubFormText>…</ng-template> |
hubValidationError | 覆盖指定错误键的提示消息。 | <ng-template hubValidationError key="min">…</ng-template> |
hubLegend | 自定义 fieldset 的 legend 内容。 | <ng-template hubLegend>…</ng-template> |
ng-option-tmp (hub-select) | 自定义下拉选项渲染(重新导出的 ng-select 指令)。 | <ng-template ng-option-tmp let-item="item">…</ng-template> |
hubFileIcon (hub-file-input) | 无缩略图文件的单文件图标;以隐式上下文接收该条目。 | <ng-template hubFileIcon let-item>…</ng-template> |
hubFilePreview (hub-file-input) | 完全替换所选文件的渲染,并接收该条目以及移除、重试和取消操作。 | <ng-template hubFilePreview let-item let-remove="remove">…</ng-template> |
hubFileDropzoneNotice (hub-file-input) | 在拖放区顶部、图标上方投影任意标记 —— 用于提示语和限制说明都无法表达的通知。 | <p hubFileDropzoneNotice>2 documents still missing</p> |
hubSegmentedOption (hub-segmented) | 替换每个分段的内容(图标、徽章、富文本标记),组件仍负责选择、键盘导航与 ARIA。上下文:选项(隐式)、selected 与 index。 | <ng-template hubSegmentedOption let-option let-selected="selected" let-index="index">…</ng-template> |
hubSelectSuffix (hub-select,已弃用) | 自 22.16.0 起弃用——请使用 [hubAppend],它在所有字段上都能做同样的事。它仍可继续使用;两者同时存在时以 [hubAppend] 为准。在下拉选择器的行末边缘附加一个可交互控件:一个作用于当前选中项的按钮——配置它、查询它、新建一个。它被声明为模板而非投影内容,因为选择器的通用 ng-content 负责把 ng-option 传给底层引擎,会把它一并吞掉;从模板渲染还能让操作在 DOM 中位于控件之后,因此 Tab 会先到达字段、再到作用于它的按钮。控件与操作共用一条边框,读起来是同一个字段。 | <ng-template hubSelectSuffix><button …>…</button></ng-template> |
hubPrepend / hubAppend (all box-shaped fields) | 附加在字段边缘的内容,比 prepend / append 字符串能承载的更丰富:一个图标,或一个作用于该值的按钮。所有渲染为「装着值的框」的字段都支持——hub-input、hub-select、hub-textarea 和 hub-datepicker。它与字符串附加标签组合而非取代:字符串先渲染,因此投影内容始终位于该侧最外层——单位标注字段,操作位于其外。投影内容采用字段的边框、圆角与高度而非自身的,因此按钮不会在控件旁画出第二条更粗的接缝。之所以声明为模板,是因为字段的 ng-content 已另有用途。 插槽也可以放入另一个字段——hub-input、hub-select、hub-textarea 或 hub-datepicker 作为直接子元素——它会与宿主字段严丝合缝地相接,使价格与其计价周期读作它们本来就是的同一句话。 | <ng-template hubAppend><button …><hub-icon … /></button></ng-template> |