fix: select deep watch options, close #5398
parent
e146b4847d
commit
3613eceff8
|
@ -42,7 +42,7 @@ import { toArray } from './utils/commonUtil';
|
||||||
import useFilterOptions from './hooks/useFilterOptions';
|
import useFilterOptions from './hooks/useFilterOptions';
|
||||||
import useCache from './hooks/useCache';
|
import useCache from './hooks/useCache';
|
||||||
import type { Key, VueNode } from '../_util/type';
|
import type { Key, VueNode } from '../_util/type';
|
||||||
import { computed, defineComponent, ref, toRef, watchEffect } from 'vue';
|
import { computed, defineComponent, ref, shallowRef, toRef, watchEffect } from 'vue';
|
||||||
import type { ExtractPropTypes, PropType } from 'vue';
|
import type { ExtractPropTypes, PropType } from 'vue';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import { initDefaultProps } from '../_util/props-util';
|
import { initDefaultProps } from '../_util/props-util';
|
||||||
|
@ -314,13 +314,15 @@ export default defineComponent({
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fill tag as option if mode is `tags`
|
// Fill tag as option if mode is `tags`
|
||||||
const filledTagOptions = computed(() => {
|
const filledTagOptions = shallowRef();
|
||||||
|
watchEffect(() => {
|
||||||
if (props.mode !== 'tags') {
|
if (props.mode !== 'tags') {
|
||||||
return mergedOptions.value;
|
filledTagOptions.value = mergedOptions.value;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// >>> Tag mode
|
// >>> Tag mode
|
||||||
const cloneOptions = [...mergedOptions.value];
|
const cloneOptions = mergedOptions.value.slice();
|
||||||
|
|
||||||
// Check if value exist in options (include new patch item)
|
// Check if value exist in options (include new patch item)
|
||||||
const existOptions = (val: RawValueType) => valueOptions.value.has(val);
|
const existOptions = (val: RawValueType) => valueOptions.value.has(val);
|
||||||
|
@ -336,7 +338,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return cloneOptions;
|
filledTagOptions.value = cloneOptions;
|
||||||
});
|
});
|
||||||
|
|
||||||
const filteredOptions = useFilterOptions(
|
const filteredOptions = useFilterOptions(
|
||||||
|
|
|
@ -7,15 +7,15 @@ import type {
|
||||||
BaseOptionType,
|
BaseOptionType,
|
||||||
} from '../Select';
|
} from '../Select';
|
||||||
import { injectPropsWithOption } from '../utils/valueUtil';
|
import { injectPropsWithOption } from '../utils/valueUtil';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref, ShallowRef } from 'vue';
|
||||||
import { toRaw, computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
function includes(test: any, search: string) {
|
function includes(test: any, search: string) {
|
||||||
return toArray(test).join('').toUpperCase().includes(search);
|
return toArray(test).join('').toUpperCase().includes(search);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (
|
export default (
|
||||||
options: Ref<DefaultOptionType[]>,
|
options: ShallowRef<DefaultOptionType[]>,
|
||||||
fieldNames: Ref<FieldNames>,
|
fieldNames: Ref<FieldNames>,
|
||||||
searchValue?: Ref<string>,
|
searchValue?: Ref<string>,
|
||||||
filterOption?: Ref<SelectProps['filterOption']>,
|
filterOption?: Ref<SelectProps['filterOption']>,
|
||||||
|
@ -55,7 +55,7 @@ export default (
|
||||||
? opt => injectPropsWithOption(opt)
|
? opt => injectPropsWithOption(opt)
|
||||||
: opt => opt;
|
: opt => opt;
|
||||||
|
|
||||||
toRaw(options.value).forEach(item => {
|
options.value.forEach(item => {
|
||||||
// Group should check child options
|
// Group should check child options
|
||||||
if (item[fieldOptions]) {
|
if (item[fieldOptions]) {
|
||||||
// Check group first
|
// Check group first
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import { toRaw, shallowRef, watchEffect } from 'vue';
|
import { toRaw, shallowRef, watchEffect, watch } from 'vue';
|
||||||
import type { FieldNames, RawValueType } from '../Select';
|
import type { FieldNames, RawValueType } from '../Select';
|
||||||
import { convertChildrenToData } from '../utils/legacyUtil';
|
import { convertChildrenToData } from '../utils/legacyUtil';
|
||||||
|
|
||||||
|
@ -15,13 +15,20 @@ export default function useOptions<OptionType>(
|
||||||
const mergedOptions = shallowRef();
|
const mergedOptions = shallowRef();
|
||||||
const valueOptions = shallowRef();
|
const valueOptions = shallowRef();
|
||||||
const labelOptions = shallowRef();
|
const labelOptions = shallowRef();
|
||||||
watchEffect(() => {
|
const tempMergedOptions = shallowRef([]);
|
||||||
let newOptions = toRaw(options.value);
|
watch(
|
||||||
const childrenAsData = !options.value;
|
[options, children],
|
||||||
|
() => {
|
||||||
if (childrenAsData) {
|
if (options.value) {
|
||||||
newOptions = convertChildrenToData(children.value);
|
tempMergedOptions.value = toRaw(options.value).slice();
|
||||||
|
} else {
|
||||||
|
tempMergedOptions.value = convertChildrenToData(children.value);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true, deep: true },
|
||||||
|
);
|
||||||
|
watchEffect(() => {
|
||||||
|
const newOptions = tempMergedOptions.value;
|
||||||
|
|
||||||
const newValueOptions = new Map<RawValueType, OptionType>();
|
const newValueOptions = new Map<RawValueType, OptionType>();
|
||||||
const newLabelOptions = new Map<any, OptionType>();
|
const newLabelOptions = new Map<any, OptionType>();
|
||||||
|
|
|
@ -98,7 +98,7 @@ export default defineComponent({
|
||||||
);
|
);
|
||||||
const mergedExpandedKeys = computed(() => {
|
const mergedExpandedKeys = computed(() => {
|
||||||
if (legacyContext.treeExpandedKeys) {
|
if (legacyContext.treeExpandedKeys) {
|
||||||
return toRaw(legacyContext.treeExpandedKeys).slice();
|
return legacyContext.treeExpandedKeys.slice();
|
||||||
}
|
}
|
||||||
return baseProps.searchValue ? searchExpandedKeys.value : expandedKeys.value;
|
return baseProps.searchValue ? searchExpandedKeys.value : expandedKeys.value;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import { toRaw, computed, shallowRef } from 'vue';
|
import { watch, toRaw, computed, shallowRef } from 'vue';
|
||||||
import type { LabeledValueType, RawValueType } from '../TreeSelect';
|
import type { LabeledValueType, RawValueType } from '../TreeSelect';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,12 +10,19 @@ export default (values: Ref<LabeledValueType[]>): [Ref<LabeledValueType[]>] => {
|
||||||
const cacheRef = shallowRef({
|
const cacheRef = shallowRef({
|
||||||
valueLabels: new Map<RawValueType, any>(),
|
valueLabels: new Map<RawValueType, any>(),
|
||||||
});
|
});
|
||||||
|
const mergedValues = shallowRef();
|
||||||
|
watch(
|
||||||
|
values,
|
||||||
|
() => {
|
||||||
|
mergedValues.value = toRaw(values.value);
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
const newFilledValues = computed(() => {
|
const newFilledValues = computed(() => {
|
||||||
const { valueLabels } = cacheRef.value;
|
const { valueLabels } = cacheRef.value;
|
||||||
const valueLabelsCache = new Map<RawValueType, any>();
|
const valueLabelsCache = new Map<RawValueType, any>();
|
||||||
|
|
||||||
const filledValues = toRaw(values.value).map(item => {
|
const filledValues = mergedValues.value.map(item => {
|
||||||
const { value } = item;
|
const { value } = item;
|
||||||
const mergedLabel = item.label ?? valueLabels.get(value);
|
const mergedLabel = item.label ?? valueLabels.get(value);
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,11 @@ import type { DataEntity } from '../../vc-tree/interface';
|
||||||
import { conductCheck } from '../../vc-tree/utils/conductUtil';
|
import { conductCheck } from '../../vc-tree/utils/conductUtil';
|
||||||
import type { LabeledValueType, RawValueType } from '../TreeSelect';
|
import type { LabeledValueType, RawValueType } from '../TreeSelect';
|
||||||
import type { Ref, ShallowRef } from 'vue';
|
import type { Ref, ShallowRef } from 'vue';
|
||||||
import { toRaw, shallowRef, watchEffect } from 'vue';
|
import { shallowRef, watchEffect } from 'vue';
|
||||||
|
|
||||||
export default (
|
export default (
|
||||||
rawLabeledValues: Ref<LabeledValueType[]>,
|
rawLabeledValues: ShallowRef<LabeledValueType[]>,
|
||||||
rawHalfCheckedValues: Ref<LabeledValueType[]>,
|
rawHalfCheckedValues: ShallowRef<LabeledValueType[]>,
|
||||||
treeConduction: Ref<boolean>,
|
treeConduction: Ref<boolean>,
|
||||||
keyEntities: Ref<Record<Key, DataEntity>>,
|
keyEntities: Ref<Record<Key, DataEntity>>,
|
||||||
maxLevel: Ref<number>,
|
maxLevel: Ref<number>,
|
||||||
|
@ -17,10 +17,8 @@ export default (
|
||||||
const newRawHalfCheckedValues = shallowRef<RawValueType[]>([]);
|
const newRawHalfCheckedValues = shallowRef<RawValueType[]>([]);
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
let checkedKeys: RawValueType[] = toRaw(rawLabeledValues.value).map(({ value }) => value);
|
let checkedKeys: RawValueType[] = rawLabeledValues.value.map(({ value }) => value);
|
||||||
let halfCheckedKeys: RawValueType[] = toRaw(rawHalfCheckedValues.value).map(
|
let halfCheckedKeys: RawValueType[] = rawHalfCheckedValues.value.map(({ value }) => value);
|
||||||
({ value }) => value,
|
|
||||||
);
|
|
||||||
|
|
||||||
const missingValues = checkedKeys.filter(key => !keyEntities.value[key]);
|
const missingValues = checkedKeys.filter(key => !keyEntities.value[key]);
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,16 @@ import type { DataEntity } from '../../vc-tree/interface';
|
||||||
import type { FieldNames, RawValueType } from '../TreeSelect';
|
import type { FieldNames, RawValueType } from '../TreeSelect';
|
||||||
|
|
||||||
import { isNil } from '../utils/valueUtil';
|
import { isNil } from '../utils/valueUtil';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref, ShallowRef } from 'vue';
|
||||||
import { toRaw, ref, watchEffect } from 'vue';
|
import { shallowRef, watchEffect } from 'vue';
|
||||||
import { warning } from '../../vc-util/warning';
|
import { warning } from '../../vc-util/warning';
|
||||||
|
|
||||||
export default (treeData: Ref<any>, fieldNames: Ref<FieldNames>) => {
|
export default (treeData: ShallowRef<any>, fieldNames: Ref<FieldNames>) => {
|
||||||
const valueEntities = ref<Map<RawValueType, DataEntity>>(new Map());
|
const valueEntities = shallowRef<Map<RawValueType, DataEntity>>(new Map());
|
||||||
const keyEntities = ref<Record<string, DataEntity>>({});
|
const keyEntities = shallowRef<Record<string, DataEntity>>({});
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const fieldNamesValue = fieldNames.value;
|
const fieldNamesValue = fieldNames.value;
|
||||||
const collection = convertDataToEntities(toRaw(treeData.value), {
|
const collection = convertDataToEntities(treeData.value, {
|
||||||
fieldNames: fieldNamesValue,
|
fieldNames: fieldNamesValue,
|
||||||
initWrapper: wrapper => ({
|
initWrapper: wrapper => ({
|
||||||
...wrapper,
|
...wrapper,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { Ref } from 'vue';
|
import type { Ref, ShallowRef } from 'vue';
|
||||||
import { toRaw, computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import type { DefaultOptionType, InternalFieldName, TreeSelectProps } from '../TreeSelect';
|
import type { DefaultOptionType, InternalFieldName, TreeSelectProps } from '../TreeSelect';
|
||||||
import { fillLegacyProps } from '../utils/legacyUtil';
|
import { fillLegacyProps } from '../utils/legacyUtil';
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ type GetFuncType<T> = T extends boolean ? never : T;
|
||||||
type FilterFn = GetFuncType<TreeSelectProps['filterTreeNode']>;
|
type FilterFn = GetFuncType<TreeSelectProps['filterTreeNode']>;
|
||||||
|
|
||||||
export default (
|
export default (
|
||||||
treeData: Ref<DefaultOptionType[]>,
|
treeData: ShallowRef<DefaultOptionType[]>,
|
||||||
searchValue: Ref<string>,
|
searchValue: Ref<string>,
|
||||||
{
|
{
|
||||||
treeNodeFilterProp,
|
treeNodeFilterProp,
|
||||||
|
@ -56,24 +56,8 @@ export default (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
// return list
|
|
||||||
// .map(dataNode => {
|
|
||||||
// const children = dataNode[fieldChildren];
|
|
||||||
|
|
||||||
// const match = keepAll || filterOptionFunc(searchValueVal, fillLegacyProps(dataNode));
|
|
||||||
// const childList = dig(children || [], match);
|
|
||||||
|
|
||||||
// if (match || childList.length) {
|
|
||||||
// return {
|
|
||||||
// ...dataNode,
|
|
||||||
// [fieldChildren]: childList,
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// })
|
|
||||||
// .filter(node => node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dig(toRaw(treeData.value));
|
return dig(treeData.value);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { Ref } from 'vue';
|
import type { Ref, ShallowRef } from 'vue';
|
||||||
import { toRaw, computed } from 'vue';
|
import { shallowRef, watch, toRaw } from 'vue';
|
||||||
import type { DataNode, SimpleModeConfig } from '../interface';
|
import type { DataNode, SimpleModeConfig } from '../interface';
|
||||||
import { convertChildrenToData } from '../utils/legacyUtil';
|
import { convertChildrenToData } from '../utils/legacyUtil';
|
||||||
import type { DefaultOptionType } from '../TreeSelect';
|
import type { DefaultOptionType } from '../TreeSelect';
|
||||||
|
@ -49,20 +49,26 @@ export default function useTreeData(
|
||||||
treeData: Ref<DataNode[]>,
|
treeData: Ref<DataNode[]>,
|
||||||
children: Ref<VueNode[]>,
|
children: Ref<VueNode[]>,
|
||||||
simpleMode: Ref<boolean | SimpleModeConfig>,
|
simpleMode: Ref<boolean | SimpleModeConfig>,
|
||||||
): Ref<DefaultOptionType[]> {
|
): ShallowRef<DefaultOptionType[]> {
|
||||||
return computed(() => {
|
const mergedTreeData = shallowRef<DefaultOptionType[]>();
|
||||||
|
watch(
|
||||||
|
[simpleMode, treeData, children],
|
||||||
|
() => {
|
||||||
const simpleModeValue = simpleMode.value;
|
const simpleModeValue = simpleMode.value;
|
||||||
if (treeData.value) {
|
if (treeData.value) {
|
||||||
return simpleMode.value
|
mergedTreeData.value = simpleMode.value
|
||||||
? parseSimpleTreeData(toRaw(treeData.value), {
|
? parseSimpleTreeData(toRaw(treeData.value), {
|
||||||
id: 'id',
|
id: 'id',
|
||||||
pId: 'pId',
|
pId: 'pId',
|
||||||
rootPId: null,
|
rootPId: null,
|
||||||
...(simpleModeValue !== true ? simpleModeValue : {}),
|
...(simpleModeValue !== true ? simpleModeValue : {}),
|
||||||
})
|
})
|
||||||
: treeData.value;
|
: toRaw(treeData.value);
|
||||||
|
} else {
|
||||||
|
mergedTreeData.value = convertChildrenToData(toRaw(children.value));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
return convertChildrenToData(toRaw(children.value));
|
{ immediate: true, deep: true },
|
||||||
});
|
);
|
||||||
|
return mergedTreeData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,12 +104,16 @@ export default defineComponent({
|
||||||
dragOverNodeKey: null,
|
dragOverNodeKey: null,
|
||||||
});
|
});
|
||||||
const treeData = shallowRef([]);
|
const treeData = shallowRef([]);
|
||||||
watchEffect(() => {
|
watch(
|
||||||
|
[() => props.treeData, () => props.children],
|
||||||
|
() => {
|
||||||
treeData.value =
|
treeData.value =
|
||||||
props.treeData !== undefined
|
props.treeData !== undefined
|
||||||
? toRaw(props.treeData)
|
? toRaw(props.treeData)
|
||||||
: convertTreeToData(toRaw(props.children));
|
: convertTreeToData(toRaw(props.children));
|
||||||
});
|
},
|
||||||
|
{ immediate: true, deep: true },
|
||||||
|
);
|
||||||
const keyEntities = shallowRef({});
|
const keyEntities = shallowRef({});
|
||||||
|
|
||||||
const focused = ref(false);
|
const focused = ref(false);
|
||||||
|
@ -143,7 +147,7 @@ export default defineComponent({
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (treeData.value) {
|
if (treeData.value) {
|
||||||
const entitiesMap = convertDataToEntities(toRaw(treeData.value), {
|
const entitiesMap = convertDataToEntities(treeData.value, {
|
||||||
fieldNames: fieldNames.value,
|
fieldNames: fieldNames.value,
|
||||||
});
|
});
|
||||||
keyEntities.value = {
|
keyEntities.value = {
|
||||||
|
@ -190,19 +194,15 @@ export default defineComponent({
|
||||||
// ================ flattenNodes =================
|
// ================ flattenNodes =================
|
||||||
const flattenNodes = shallowRef([]);
|
const flattenNodes = shallowRef([]);
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
flattenNodes.value = flattenTreeData(
|
flattenNodes.value = flattenTreeData(treeData.value, expandedKeys.value, fieldNames.value);
|
||||||
toRaw(treeData.value),
|
|
||||||
toRaw(expandedKeys.value),
|
|
||||||
fieldNames.value,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
// ================ selectedKeys =================
|
// ================ selectedKeys =================
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (props.selectable) {
|
if (props.selectable) {
|
||||||
if (props.selectedKeys !== undefined) {
|
if (props.selectedKeys !== undefined) {
|
||||||
selectedKeys.value = calcSelectedKeys(toRaw(props.selectedKeys), props);
|
selectedKeys.value = calcSelectedKeys(props.selectedKeys, props);
|
||||||
} else if (!init && props.defaultSelectedKeys) {
|
} else if (!init && props.defaultSelectedKeys) {
|
||||||
selectedKeys.value = calcSelectedKeys(toRaw(props.defaultSelectedKeys), props);
|
selectedKeys.value = calcSelectedKeys(props.defaultSelectedKeys, props);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -213,12 +213,12 @@ export default defineComponent({
|
||||||
let checkedKeyEntity;
|
let checkedKeyEntity;
|
||||||
|
|
||||||
if (props.checkedKeys !== undefined) {
|
if (props.checkedKeys !== undefined) {
|
||||||
checkedKeyEntity = parseCheckedKeys(toRaw(props.checkedKeys)) || {};
|
checkedKeyEntity = parseCheckedKeys(props.checkedKeys) || {};
|
||||||
} else if (!init && props.defaultCheckedKeys) {
|
} else if (!init && props.defaultCheckedKeys) {
|
||||||
checkedKeyEntity = parseCheckedKeys(toRaw(props.defaultCheckedKeys)) || {};
|
checkedKeyEntity = parseCheckedKeys(props.defaultCheckedKeys) || {};
|
||||||
} else if (treeData.value) {
|
} else if (treeData.value) {
|
||||||
// If `treeData` changed, we also need check it
|
// If `treeData` changed, we also need check it
|
||||||
checkedKeyEntity = parseCheckedKeys(toRaw(props.checkedKeys)) || {
|
checkedKeyEntity = parseCheckedKeys(props.checkedKeys) || {
|
||||||
checkedKeys: checkedKeys.value,
|
checkedKeys: checkedKeys.value,
|
||||||
halfCheckedKeys: halfCheckedKeys.value,
|
halfCheckedKeys: halfCheckedKeys.value,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue