ant-design-vue/components/vc-form/src/createFieldsStore.jsx

262 lines
6.7 KiB
Vue

import set from 'lodash/set'
import createFormField, { isFormField } from './createFormField'
import {
flattenFields,
getErrorStrs,
startsWith,
} from './utils'
function partOf (a, b) {
return b.indexOf(a) === 0 && ['.', '['].indexOf(b[a.length]) !== -1
}
class FieldsStore {
constructor (fields) {
this.fields = this.flattenFields(fields)
this.fieldsMeta = {}
}
updateFields (fields) {
this.fields = this.flattenFields(fields)
}
flattenFields (fields) {
return flattenFields(
fields,
(_, node) => isFormField(node),
'You must wrap field data with `createFormField`.'
)
}
flattenRegisteredFields (fields) {
const validFieldsName = this.getAllFieldsName()
return flattenFields(
fields,
path => validFieldsName.indexOf(path) >= 0,
'You cannot set field before registering it.'
)
}
setFieldsInitialValue = (initialValues) => {
const flattenedInitialValues = this.flattenRegisteredFields(initialValues)
const fieldsMeta = this.fieldsMeta
Object.keys(flattenedInitialValues).forEach(name => {
if (fieldsMeta[name]) {
this.setFieldMeta(name, {
...this.getFieldMeta(name),
initialValue: flattenedInitialValues[name],
})
}
})
}
setFields (fields) {
const fieldsMeta = this.fieldsMeta
const nowFields = {
...this.fields,
...fields,
}
const nowValues = {}
Object.keys(fieldsMeta)
.forEach((f) => { nowValues[f] = this.getValueFromFields(f, nowFields) })
Object.keys(nowValues).forEach((f) => {
const value = nowValues[f]
const fieldMeta = this.getFieldMeta(f)
if (fieldMeta && fieldMeta.normalize) {
const nowValue =
fieldMeta.normalize(value, this.getValueFromFields(f, this.fields), nowValues)
if (nowValue !== value) {
nowFields[f] = {
...nowFields[f],
value: nowValue,
}
}
}
})
this.fields = nowFields
}
resetFields (ns) {
const { fields } = this
const names = ns
? this.getValidFieldsFullName(ns)
: this.getAllFieldsName()
return names.reduce((acc, name) => {
const field = fields[name]
if (field && 'value' in field) {
acc[name] = {}
}
return acc
}, {})
}
setFieldMeta (name, meta) {
this.fieldsMeta[name] = meta
}
getFieldMeta (name) {
this.fieldsMeta[name] = this.fieldsMeta[name] || {}
return this.fieldsMeta[name]
}
getValueFromFields (name, fields) {
const field = fields[name]
if (field && 'value' in field) {
return field.value
}
const fieldMeta = this.getFieldMeta(name)
return fieldMeta && fieldMeta.initialValue
}
getAllValues = () => {
const { fieldsMeta, fields } = this
return Object.keys(fieldsMeta)
.reduce((acc, name) => set(acc, name, this.getValueFromFields(name, fields)), {})
}
getValidFieldsName () {
const { fieldsMeta } = this
return fieldsMeta
? Object.keys(fieldsMeta).filter(name => !this.getFieldMeta(name).hidden)
: []
}
getAllFieldsName () {
const { fieldsMeta } = this
return fieldsMeta ? Object.keys(fieldsMeta) : []
}
getValidFieldsFullName (maybePartialName) {
const maybePartialNames = Array.isArray(maybePartialName)
? maybePartialName : [maybePartialName]
return this.getValidFieldsName()
.filter(fullName => maybePartialNames.some(partialName => (
fullName === partialName || (
startsWith(fullName, partialName) &&
['.', '['].indexOf(fullName[partialName.length]) >= 0
)
)))
}
getFieldValuePropValue (fieldMeta) {
const { name, getValueProps, valuePropName } = fieldMeta
const field = this.getField(name)
const fieldValue = 'value' in field
? field.value : fieldMeta.initialValue
if (getValueProps) {
return getValueProps(fieldValue)
}
return { [valuePropName]: fieldValue }
}
getField (name) {
return {
...this.fields[name],
name,
}
}
getNotCollectedFields () {
return this.getValidFieldsName()
.filter(name => !this.fields[name])
.map(name => ({
name,
dirty: false,
value: this.getFieldMeta(name).initialValue,
}))
.reduce((acc, field) => set(acc, field.name, createFormField(field)), {})
}
getNestedAllFields () {
return Object.keys(this.fields)
.reduce(
(acc, name) => set(acc, name, createFormField(this.fields[name])),
this.getNotCollectedFields()
)
}
getFieldMember (name, member) {
return this.getField(name)[member]
}
getNestedFields (names, getter) {
const fields = names || this.getValidFieldsName()
return fields.reduce((acc, f) => set(acc, f, getter(f)), {})
}
getNestedField (name, getter) {
const fullNames = this.getValidFieldsFullName(name)
if (
fullNames.length === 0 || // Not registered
(fullNames.length === 1 && fullNames[0] === name) // Name already is full name.
) {
return getter(name)
}
const isArrayValue = fullNames[0][name.length] === '['
const suffixNameStartIndex = isArrayValue ? name.length : name.length + 1
return fullNames
.reduce(
(acc, fullName) => set(
acc,
fullName.slice(suffixNameStartIndex),
getter(fullName)
),
isArrayValue ? [] : {}
)
}
getFieldsValue = (names) => {
return this.getNestedFields(names, this.getFieldValue)
}
getFieldValue = (name) => {
const { fields } = this
return this.getNestedField(name, (fullName) => this.getValueFromFields(fullName, fields))
}
getFieldsError = (names) => {
return this.getNestedFields(names, this.getFieldError)
}
getFieldError = (name) => {
return this.getNestedField(
name,
(fullName) => getErrorStrs(this.getFieldMember(fullName, 'errors'))
)
}
isFieldValidating = (name) => {
return this.getFieldMember(name, 'validating')
}
isFieldsValidating = (ns) => {
const names = ns || this.getValidFieldsName()
return names.some((n) => this.isFieldValidating(n))
}
isFieldTouched = (name) => {
return this.getFieldMember(name, 'touched')
}
isFieldsTouched = (ns) => {
const names = ns || this.getValidFieldsName()
return names.some((n) => this.isFieldTouched(n))
}
// @private
// BG: `a` and `a.b` cannot be use in the same form
isValidNestedFieldName (name) {
const names = this.getAllFieldsName()
return names.every(n => !partOf(n, name) && !partOf(name, n))
}
clearField (name) {
delete this.fields[name]
delete this.fieldsMeta[name]
}
}
export default function createFieldsStore (fields) {
return new FieldsStore(fields)
}