mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
feat(components): [form] export getField (#20981)
* feat(components): [form] export getField * fix(components): [form] test * feat(components): [form] export getField * Update packages/components/form/src/utils.ts Co-authored-by: btea <2356281422@qq.com> * feat(components): [form] export getField * feat(components): [form] export getField --------- Co-authored-by: btea <2356281422@qq.com>
This commit is contained in:
@@ -160,14 +160,15 @@ form/accessibility
|
||||
|
||||
### Form Exposes
|
||||
|
||||
| Name | Description | Type |
|
||||
| --------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| validate | Validate the whole form. Receives a callback or returns `Promise`. | ^[Function]`(callback?: FormValidateCallback) => Promise<void>` |
|
||||
| validateField | Validate specified fields. | ^[Function]`(props?: Arrayable<FormItemProp> \| undefined, callback?: FormValidateCallback \| undefined) => FormValidationResult` |
|
||||
| resetFields | Reset specified fields and remove validation result. | ^[Function]`(props?: Arrayable<FormItemProp> \| undefined) => void` |
|
||||
| scrollToField | Scroll to the specified fields. | ^[Function]`(prop: FormItemProp) => void` |
|
||||
| clearValidate | Clear validation messages for all or specified fields. | ^[Function]`(props?: Arrayable<FormItemProp> \| undefined) => void` |
|
||||
| fields ^(2.7.3) | Get all fields context. | ^[array]`FormItemContext[]` |
|
||||
| Name | Description | Type |
|
||||
| ------------------ | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| validate | Validate the whole form. Receives a callback or returns `Promise`. | ^[Function]`(callback?: FormValidateCallback) => Promise<void>` |
|
||||
| validateField | Validate specified fields. | ^[Function]`(props?: Arrayable<FormItemProp> \| undefined, callback?: FormValidateCallback \| undefined) => FormValidationResult` |
|
||||
| resetFields | Reset specified fields and remove validation result. | ^[Function]`(props?: Arrayable<FormItemProp> \| undefined) => void` |
|
||||
| scrollToField | Scroll to the specified fields. | ^[Function]`(prop: FormItemProp) => void` |
|
||||
| clearValidate | Clear validation messages for all or specified fields. | ^[Function]`(props?: Arrayable<FormItemProp> \| undefined) => void` |
|
||||
| fields ^(2.7.3) | Get all fields context. | ^[array]`FormItemContext[]` |
|
||||
| getField ^(2.10.2) | Get a field context. | ^[Function]`(prop: FormItemProp) => FormItemContext \| undefined` |
|
||||
|
||||
## FormItem API
|
||||
|
||||
@@ -279,12 +280,14 @@ type FormItemProps = ExtractPropTypes<typeof formItemProps>
|
||||
type FormItemContext = FormItemProps & {
|
||||
$el: HTMLDivElement | undefined
|
||||
size: ComponentSize
|
||||
validateMessage: string
|
||||
validateState: FormItemValidateState
|
||||
isGroup: boolean
|
||||
labelId: string
|
||||
inputIds: string[]
|
||||
hasLabel: boolean
|
||||
fieldValue: any
|
||||
propString: string
|
||||
addInputId: (id: string) => void
|
||||
removeInputId: (id: string) => void
|
||||
validate: (
|
||||
|
||||
@@ -850,6 +850,64 @@ describe('Form', () => {
|
||||
expect(fn).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('prop is array', async () => {
|
||||
vi.useFakeTimers()
|
||||
const wrapper = mount({
|
||||
setup() {
|
||||
const form = reactive({
|
||||
obj: { name: '' },
|
||||
})
|
||||
const rules = {
|
||||
required: true,
|
||||
message: 'Please input name',
|
||||
trigger: 'blur',
|
||||
}
|
||||
return () => (
|
||||
<Form ref="formRef" model={form}>
|
||||
<FormItem
|
||||
label="Name"
|
||||
ref="name"
|
||||
prop={['obj', 'name']}
|
||||
rules={rules}
|
||||
>
|
||||
<Input v-model={form.obj.name} />
|
||||
</FormItem>
|
||||
</Form>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
await nextTick()
|
||||
|
||||
const formRef = wrapper.vm.$refs.formRef as FormInstance
|
||||
const valid = await formRef
|
||||
.validateField([['obj', 'name']])
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
expect(valid).toEqual(false)
|
||||
vi.runAllTimers()
|
||||
await nextTick()
|
||||
expect(wrapper.find('.is-error').exists()).toBe(true)
|
||||
expect(wrapper.find('.el-form-item__error').text()).toBe(
|
||||
'Please input name'
|
||||
)
|
||||
|
||||
formRef.resetFields([['obj', 'name']])
|
||||
await nextTick()
|
||||
vi.runAllTimers()
|
||||
await nextTick()
|
||||
expect(wrapper.find('.is-error').exists()).toBe(false)
|
||||
|
||||
const field = formRef.getField(['obj', 'name'])
|
||||
field.validateState = 'error'
|
||||
field.validateMessage = 'name is error'
|
||||
vi.runAllTimers()
|
||||
await nextTick()
|
||||
expect(wrapper.find('.is-error').exists()).toBe(true)
|
||||
expect(wrapper.find('.el-form-item__error').text()).toBe('name is error')
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
describe('FormItem', () => {
|
||||
const onSuccess = vi.fn()
|
||||
const onError = vi.fn()
|
||||
|
||||
@@ -60,7 +60,6 @@ import {
|
||||
isArray,
|
||||
isBoolean,
|
||||
isFunction,
|
||||
isString,
|
||||
} from '@element-plus/utils'
|
||||
import { useId, useNamespace } from '@element-plus/hooks'
|
||||
import { useFormSize } from './hooks'
|
||||
@@ -159,7 +158,7 @@ const validateClasses = computed(() => [
|
||||
|
||||
const propString = computed(() => {
|
||||
if (!props.prop) return ''
|
||||
return isString(props.prop) ? props.prop : props.prop.join('.')
|
||||
return isArray(props.prop) ? props.prop.join('.') : props.prop
|
||||
})
|
||||
|
||||
const hasLabel = computed<boolean>(() => {
|
||||
@@ -382,6 +381,7 @@ const context: FormItemContext = reactive({
|
||||
...toRefs(props),
|
||||
$el: formItemRef,
|
||||
size: _size,
|
||||
validateMessage,
|
||||
validateState,
|
||||
labelId,
|
||||
inputIds,
|
||||
@@ -393,6 +393,7 @@ const context: FormItemContext = reactive({
|
||||
resetField,
|
||||
clearValidate,
|
||||
validate,
|
||||
propString,
|
||||
})
|
||||
|
||||
provide(formItemContextKey, context)
|
||||
|
||||
@@ -48,7 +48,7 @@ const formClasses = computed(() => {
|
||||
})
|
||||
|
||||
const getField: FormContext['getField'] = (prop) => {
|
||||
return fields.find((field) => field.prop === prop)
|
||||
return filterFields(fields, [prop])[0]
|
||||
}
|
||||
|
||||
const addField: FormContext['addField'] = (field) => {
|
||||
@@ -155,7 +155,7 @@ const validateField: FormContext['validateField'] = async (
|
||||
}
|
||||
|
||||
const scrollToField = (prop: FormItemProp) => {
|
||||
const field = filterFields(fields, prop)[0]
|
||||
const field = getField(prop)
|
||||
if (field) {
|
||||
field.$el?.scrollIntoView(props.scrollIntoViewOptions)
|
||||
}
|
||||
@@ -209,6 +209,10 @@ defineExpose({
|
||||
* @description Scroll to the specified fields.
|
||||
*/
|
||||
scrollToField,
|
||||
/**
|
||||
* @description Get a field context.
|
||||
*/
|
||||
getField,
|
||||
/**
|
||||
* @description All fields context.
|
||||
*/
|
||||
|
||||
@@ -113,7 +113,7 @@ export interface FormValidateFailure {
|
||||
export type FormContext = FormProps &
|
||||
UnwrapRef<FormLabelWidthContext> & {
|
||||
emit: SetupContext<FormEmits>['emit']
|
||||
getField: (prop: string) => FormItemContext | undefined
|
||||
getField: (prop: FormItemProp) => FormItemContext | undefined
|
||||
addField: (field: FormItemContext) => void
|
||||
removeField: (field: FormItemContext) => void
|
||||
resetFields: (props?: Arrayable<FormItemProp>) => void
|
||||
@@ -127,12 +127,14 @@ export type FormContext = FormProps &
|
||||
export interface FormItemContext extends FormItemProps {
|
||||
$el: HTMLDivElement | undefined
|
||||
size: ComponentSize
|
||||
validateMessage: string
|
||||
validateState: FormItemValidateState
|
||||
isGroup: boolean
|
||||
labelId: string
|
||||
inputIds: string[]
|
||||
hasLabel: boolean
|
||||
fieldValue: any
|
||||
propString: string
|
||||
addInputId: (id: string) => void
|
||||
removeInputId: (id: string) => void
|
||||
validate: (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import { debugWarn, ensureArray } from '@element-plus/utils'
|
||||
import { debugWarn, ensureArray, isArray } from '@element-plus/utils'
|
||||
import type { Arrayable } from '@element-plus/utils'
|
||||
import type { FormItemContext } from './types'
|
||||
import type { FormItemProp } from './form-item'
|
||||
@@ -50,8 +50,12 @@ export const filterFields = (
|
||||
fields: FormItemContext[],
|
||||
props: Arrayable<FormItemProp>
|
||||
) => {
|
||||
const normalized = ensureArray(props)
|
||||
const normalized = ensureArray(props).map((prop) =>
|
||||
isArray(prop) ? prop.join('.') : prop
|
||||
)
|
||||
return normalized.length > 0
|
||||
? fields.filter((field) => field.prop && normalized.includes(field.prop))
|
||||
? fields.filter(
|
||||
(field) => field.propString && normalized.includes(field.propString)
|
||||
)
|
||||
: fields
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user