mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
fix(components): [tree-select] emit change when toggling node labels (#22863)
* fix(components): [tree-select] emit change when toggling node labels closed #22862 * fix(components): [tree-select] avoid double change on checkbox closed #22862 * refactor(components): [tree-select] extract update helper closed #22862 --------- Co-authored-by: alex.yang <alex.yang@hytechc.com> Co-authored-by: 云游君 <me@yunyoujun.cn>
This commit is contained in:
@@ -499,6 +499,54 @@ describe('TreeSelect.vue', () => {
|
||||
expect(select.vm.modelValue).toBe(undefined)
|
||||
})
|
||||
|
||||
test('emit change when toggling node via label click', async () => {
|
||||
const handleChange = vi.fn()
|
||||
const { tree } = createComponent({
|
||||
props: {
|
||||
showCheckbox: true,
|
||||
checkOnClickNode: true,
|
||||
onChange: handleChange,
|
||||
},
|
||||
})
|
||||
|
||||
await nextTick()
|
||||
const target = tree.findAll('.el-tree-node__content').slice(-1)[0]
|
||||
|
||||
await target.trigger('click')
|
||||
await nextTick()
|
||||
expect(handleChange).toHaveBeenLastCalledWith(111)
|
||||
|
||||
await target.trigger('click')
|
||||
await nextTick()
|
||||
expect(handleChange).toHaveBeenLastCalledWith(undefined)
|
||||
expect(handleChange).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
test('emit change once when toggling node via checkbox click', async () => {
|
||||
const handleChange = vi.fn()
|
||||
const { tree } = createComponent({
|
||||
props: {
|
||||
showCheckbox: true,
|
||||
checkOnClickNode: true,
|
||||
onChange: handleChange,
|
||||
},
|
||||
})
|
||||
|
||||
await nextTick()
|
||||
const checkbox = tree
|
||||
.findAll('.el-tree-node__content .el-checkbox__original')
|
||||
.slice(-1)[0]
|
||||
|
||||
await checkbox.trigger('click')
|
||||
await nextTick()
|
||||
expect(handleChange).toHaveBeenLastCalledWith(111)
|
||||
|
||||
await checkbox.trigger('click')
|
||||
await nextTick()
|
||||
expect(handleChange).toHaveBeenLastCalledWith(undefined)
|
||||
expect(handleChange).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
test('expand selected node`s parent in first time', async () => {
|
||||
const value = ref(111)
|
||||
const { tree } = createComponent({
|
||||
|
||||
@@ -26,19 +26,27 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
const { slots, expose } = context
|
||||
const { slots, expose, emit, attrs } = context
|
||||
const childAttrs = {
|
||||
...attrs,
|
||||
onChange: undefined,
|
||||
}
|
||||
|
||||
const select = ref<SelectInstance>()
|
||||
const tree = ref<TreeInstance>()
|
||||
|
||||
const key = computed(() => props.nodeKey || props.valueKey || 'value')
|
||||
|
||||
const selectProps = useSelect(props, context, { select, tree, key })
|
||||
const { cacheOptions, ...treeProps } = useTree(props, context, {
|
||||
select,
|
||||
tree,
|
||||
key,
|
||||
})
|
||||
const selectProps = useSelect(props, { attrs, emit }, { select, tree, key })
|
||||
const { cacheOptions, ...treeProps } = useTree(
|
||||
props,
|
||||
{ attrs: childAttrs, slots, emit },
|
||||
{
|
||||
select,
|
||||
tree,
|
||||
key,
|
||||
}
|
||||
)
|
||||
|
||||
// expose ElTree/ElSelect methods
|
||||
const methods = reactive({})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import { computed, nextTick, toRefs, watch } from 'vue'
|
||||
import { isEqual, isNil, pick } from 'lodash-unified'
|
||||
import { UPDATE_MODEL_EVENT } from '@element-plus/constants'
|
||||
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '@element-plus/constants'
|
||||
import { escapeStringRegexp, isEmpty, isFunction } from '@element-plus/utils'
|
||||
import ElTree from '@element-plus/components/tree'
|
||||
import TreeSelectOption from './tree-select-option'
|
||||
@@ -121,6 +121,17 @@ export const useTree = (
|
||||
})
|
||||
}
|
||||
|
||||
const emitChange = (val: any | any[]) => {
|
||||
if (!isEqual(props.modelValue, val)) {
|
||||
emit(CHANGE_EVENT, val)
|
||||
}
|
||||
}
|
||||
|
||||
function update(val) {
|
||||
emit(UPDATE_MODEL_EVENT, val)
|
||||
emitChange(val)
|
||||
}
|
||||
|
||||
return {
|
||||
...pick(toRefs(props), Object.keys(ElTree.props)),
|
||||
...attrs,
|
||||
@@ -202,9 +213,8 @@ export const useTree = (
|
||||
const checkedKeys = cachedKeys.concat(uncachedCheckedKeys)
|
||||
|
||||
if (props.checkStrictly) {
|
||||
emit(
|
||||
UPDATE_MODEL_EVENT,
|
||||
// Checking for changes may come from `check-on-node-click`
|
||||
// Checking for changes may come from `check-on-node-click`
|
||||
update(
|
||||
props.multiple
|
||||
? checkedKeys
|
||||
: checkedKeys.includes(dataValue)
|
||||
@@ -213,40 +223,36 @@ export const useTree = (
|
||||
)
|
||||
}
|
||||
// only can select leaf node
|
||||
else {
|
||||
if (props.multiple) {
|
||||
const childKeys = getChildCheckedKeys()
|
||||
else if (props.multiple) {
|
||||
const childKeys = getChildCheckedKeys()
|
||||
update(cachedKeys.concat(childKeys))
|
||||
} else {
|
||||
// select first leaf node when check parent
|
||||
const firstLeaf = treeFind(
|
||||
[data],
|
||||
(data) =>
|
||||
!isValidArray(getNodeValByProp('children', data)) &&
|
||||
!getNodeValByProp('disabled', data),
|
||||
(data) => getNodeValByProp('children', data)
|
||||
)
|
||||
const firstLeafKey = firstLeaf
|
||||
? getNodeValByProp('value', firstLeaf)
|
||||
: undefined
|
||||
|
||||
emit(UPDATE_MODEL_EVENT, cachedKeys.concat(childKeys))
|
||||
} else {
|
||||
// select first leaf node when check parent
|
||||
const firstLeaf = treeFind(
|
||||
// unselect when any child checked
|
||||
const hasCheckedChild =
|
||||
isValidValue(props.modelValue) &&
|
||||
!!treeFind(
|
||||
[data],
|
||||
(data) =>
|
||||
!isValidArray(getNodeValByProp('children', data)) &&
|
||||
!getNodeValByProp('disabled', data),
|
||||
(data) => getNodeValByProp('value', data) === props.modelValue,
|
||||
(data) => getNodeValByProp('children', data)
|
||||
)
|
||||
const firstLeafKey = firstLeaf
|
||||
? getNodeValByProp('value', firstLeaf)
|
||||
: undefined
|
||||
|
||||
// unselect when any child checked
|
||||
const hasCheckedChild =
|
||||
isValidValue(props.modelValue) &&
|
||||
!!treeFind(
|
||||
[data],
|
||||
(data) => getNodeValByProp('value', data) === props.modelValue,
|
||||
(data) => getNodeValByProp('children', data)
|
||||
)
|
||||
|
||||
emit(
|
||||
UPDATE_MODEL_EVENT,
|
||||
firstLeafKey === props.modelValue || hasCheckedChild
|
||||
? undefined
|
||||
: firstLeafKey
|
||||
)
|
||||
}
|
||||
update(
|
||||
firstLeafKey === props.modelValue || hasCheckedChild
|
||||
? undefined
|
||||
: firstLeafKey
|
||||
)
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
@@ -289,7 +295,7 @@ export const useTree = (
|
||||
)
|
||||
|
||||
const childKeys = getChildCheckedKeys()
|
||||
emit(UPDATE_MODEL_EVENT, cachedKeys.concat(childKeys))
|
||||
update(cachedKeys.concat(childKeys))
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user