ng-environment-setup
Version:
ng environment setup
449 lines (419 loc) • 10.8 kB
text/typescript
import {
Component,
Input,
OnInit,
EventEmitter,
Output,
AfterViewInit,
OnChanges,
SimpleChanges,
ContentChild,
TemplateRef
} from '@angular/core'
import { FormGroup, FormBuilder, Validators } from '@angular/forms'
import { FormItem, FormConfig } from './form.interface'
import { DomSanitizer } from '@angular/platform-browser'
export class FormComponent implements OnInit, OnChanges, AfterViewInit {
// 表单ng-template模板
inputCustomTpl: TemplateRef<any>
constructor(
private fb: FormBuilder,
public sanitize: DomSanitizer
) {}
// 表单配置数组
formFields: FormItem[] = []
// 表单
form: FormGroup
// 表单数据
formData: any = {}
// 表单禁用字段列表
formDisables: any = {}
// 表单布局 'horizontal' | 'vertical' | 'inline'
layout = 'horizontal'
// 表单公共配置
config: FormConfig = {}
// 表单提交事件
refer = new EventEmitter<any>()
// 表单配置
set fields(fields: FormItem[]) {
this.formFields = fields
if (this.form) {
this.formatFields()
} else {
this.form = this.createGroup()
}
}
get fields(): FormItem[] {
return this.formFields
}
// 表单数据
set data(data: any[]) {
this.formData = data
this.setValue(data)
}
get data(): any[] {
return this.formData
}
// 表单禁用字段列表
set disableds(data: any) {
this.formDisables = Object.assign(this.formDisables, data)
}
get disableds(): any {
return this.formDisables
}
/**
* 创建表单
* @returns FormGroup 表单
*/
createGroup(): FormGroup {
const group = this.fb.group({})
this.formDisables = {}
this.formatFields((field: FormItem) => {
group.addControl(field.name, this.fb.control({
value: field.value,
}, field.validators || (field.required ? [Validators.required] : [])))
})
return group
}
/**
* 格式化表单数据
* @param cb 回调函数
*/
formatFields(cb?: (f: FormItem) => void) {
const { labelSameWidth, adaptive, ...otherConfig } = this.config || {}
const labelWidth = this.getLabelWidth(this.formFields)
this.formFields.forEach((field: FormItem) => {
// 文本输入类型
const isInputType = ['text', 'password', 'number', 'textarea'].includes(field.type)
// 只读类型
const isReadType = ['button', 'reaonly', 'split'].includes(field.type)
// 公共配置处理
Object.keys(otherConfig).forEach(key => {
if (!field.hasOwnProperty(key)) {
field[key] = this.config[key]
}
})
// 表单禁用缓存
if (field.hasOwnProperty('disabled')) {
this.formDisables[field.name] = field.disabled
}
// 非只读类型处理
if (!isReadType) {
// 表单复制
if (cb) {
cb(field)
} else {
if (field.hasOwnProperty('value')) {
this.setValue(field.name, field.value)
}
}
// 表单值变化事件
if (!field.change) {
field.change = () => {}
}
// 表单默认提示文字
if (!field.placeholder) {
field.placeholder = `${isInputType ? '请输入' : '请选择'}${field.label}`
}
// 表单默认验证提示
if (!field.autoTips && !field.validators && field.required) {
field.autoTips = {
'zh-cn': {
required: isInputType ? `${field.label}不能为空` : `请选择${field.label}`
}
}
}
if (field.autoTips && !field.autoTips['zh-cn']) {
field.autoTips = {
'zh-cn': {
...field.autoTips
}
}
}
// 表单默认样式名
if (!field.class) {
field.class = adaptive ? 'adaptive' : 'md'
}
// 表单标签同宽设置
if (labelSameWidth && !field.labelWidth && labelWidth) {
field.labelWidth = labelWidth
}
// 表单标签默认样式名
if (!field.labelClass) {
field.labelClass = ''
}
// 表单默认大小
if (!field.size) {
field.size = 'default'
}
this.fieldHandler(field)
}
})
}
/**
* 表单项处理
* @param field 字段配置
*/
fieldHandler(field): void {
switch (field.type) {
// 数字框
case 'number':
if (!field.hasOwnProperty('min')) {
field.min = -Infinity
}
if (!field.hasOwnProperty('max')) {
field.max = Infinity
}
if (!field.parser) {
field.parser = (value: string) => value.trim().replace(/。/g, '.').replace(/[^\w\.-]+/g, '')
}
if (!field.formatter) {
field.formatter = (value: number | string) => value
}
['focus', 'blur'].forEach(key => {
if (!field[key]) {
field[key] = () => {}
}
})
break
// 下拉框
case 'select':
if (!field.hasOwnProperty('maxMultipleCount')) {
field.maxMultipleCount = Infinity
}
if (!field.compareWith) {
field.compareWith = (o1: any, o2: any) => o1 === o2
}
['openChange', 'onSearch', 'scrollToBottom', 'focus', 'blur'].forEach(key => {
if (!field[key]) {
field[key] = () => {}
}
})
break
// 多级选择框
case 'cascader':
['visibleChange', 'selectionChange'].forEach(key => {
if (!field[key]) {
field[key] = () => {}
}
})
break
// 单选框
case 'radio':
field.map.forEach(item => {
if (!item.change) {
item.change = () => {}
}
})
break
// 日期选择框-日
case 'date':
['onOpenChange', 'onOk'].forEach(key => {
if (!field[key]) {
field[key] = () => {}
}
})
break
// 日期选择框-月、年、周、范围
case 'month':
case 'year':
case 'week':
case 'range':
if (!field.onOpenChange) {
field.onOpenChange = () => {}
}
break
// 日期选择框-时间
case 'time':
if (!field.openChange) {
field.openChange = () => {}
}
break
default:
break
}
}
/**
* 获取字符串宽度
* @param fontSize 字体大小
* @param text 字符串
*/
getTextWidth(fontSize, text) {
const result = { width: 0, height: 0 }
const span = document.createElement('span')
span.innerHTML = text
span.style.visibility = 'hidden'
span.style.fontSize = fontSize + 'px'
document.body.appendChild(span)
result.width = span.offsetWidth
result.height = span.offsetHeight
span.parentNode.removeChild(span)
return result.width
}
/**
* 获取标签最大宽度
* @param fields 字段配置数组
*/
getLabelWidth(fields: FormItem[]) {
if (fields instanceof Array) {
return Math.max(...fields.map(f => this.getTextWidth(14, f.label || ''))) + 25
}
return 0
}
/**
* 表单提交
*/
submit(): void {
Object.keys(this.form.controls).forEach(i => {
this.formHandler(i, 'valid')
})
if (this.form.valid) {
this.refer.emit(this.form.value)
}
}
/**
* 表单验证
*/
valid(callback?: any): boolean | void {
Object.keys(this.form.controls).forEach(i => {
this.formHandler(i, 'valid')
})
if (typeof callback === 'function') {
callback(this.form.valid)
} else {
return this.form.valid
}
}
/**
* 表单重置
*/
reset(): void {
this.formFields.forEach(field => {
if (field.type !== 'button') {
this.formHandler(field.name, 'reset', field.value)
}
})
}
/**
* 设置表单数据
* @param data 表单数据
* @param value 表单字段数值
*/
setValue(data: any, value?: any): void {
if (typeof data === 'object') {
if (Object.keys(data).length) {
Object.keys(data).forEach(i => {
this.formHandler(i, 'value', data[i])
})
} else {
this.reset()
}
}
if (typeof data === 'string') {
this.formHandler(data, 'value', value)
}
}
/**
* 设置表单数据禁用状态
* @param name 表单字段名称或字段名称数组
* @param disabled 是否禁用
*/
setDisabled(name: string[] | string, disabled: boolean): void {
if (name instanceof Array) {
name.forEach(i => {
this.formHandler(i, disabled ? 'disable' : 'enable')
})
}
if (typeof name === 'string') {
this.formHandler(name, disabled ? 'disable' : 'enable')
}
}
/**
* 更新禁用状态
*/
updateDisabled(): void {
Object.keys(this.formDisables).forEach(key => {
this.setDisabled(key, this.formDisables[key])
})
}
/**
* 表单操作
* @param name 字段名称
* @param type 操作类型
* @param params 参数
*/
formHandler(name: string, type: string, params?: any) {
const control = this.form.controls[name]
if (control) {
switch (type) {
// 启用表单
case 'enable':
control.enable({ onlySelf: true })
break;
// 禁用表单
case 'disable':
control.disable({ onlySelf: true })
break;
// 设置表单值
case 'value':
control.setValue(params)
break;
// 验证表单
case 'valid':
control.markAsDirty()
control.updateValueAndValidity()
break;
// 重置表单数据
case 'reset':
control.reset(params)
break;
default:
break;
}
}
}
/**
* 根据值和map获取名称
* @param value 值
* @param map 列表
*/
getLabelByValue(value, map) {
if (map instanceof Array) {
const findObj = map.find(x => x.value === value)
if (findObj) {
return findObj.label
}
}
return ''
}
/**
* 初始化
*/
ngOnInit() {
}
/**
* 数据变化
*/
ngOnChanges(changes: SimpleChanges) {
const { disableds } = changes
if (disableds && !disableds.firstChange) {
this.updateDisabled()
}
}
/**
* 元素获取
*/
ngAfterViewInit() {
setTimeout(() => {
this.updateDisabled()
})
}
}