Add show all/selected toggle to tree-select (#7161)

This commit is contained in:
Rijk van Zanten
2021-08-03 17:32:01 +02:00
committed by GitHub
parent b8cea5c1ac
commit fb9ee7ab30
4 changed files with 89 additions and 11 deletions

View File

@@ -1,7 +1,7 @@
<template>
<v-list-group
v-if="children"
v-show="visibleChildrenValues.length > 0"
v-show="groupShown"
:value="value"
:open="typeof search === 'string' && search.length > 0"
arrow-placement="before"
@@ -32,10 +32,11 @@
:value="choice[itemValue]"
:children="choice[itemChildren]"
:disabled="disabled"
:show-selection-only="showSelectionOnly"
/>
</v-list-group>
<v-list-item v-else-if="!children && !hidden" class="item">
<v-list-item v-else-if="!children" v-show="!hidden" class="item">
<v-checkbox v-model="treeValue" :disabled="disabled" :checked="checked" :label="text" :value="value" />
</v-list-item>
</template>
@@ -100,28 +101,57 @@ export default defineComponent({
type: Boolean,
default: false,
},
showSelectionOnly: {
type: Boolean,
default: false,
},
},
emits: ['update:modelValue'],
setup(props, { emit }) {
const visibleChildrenValues = computed(() => {
if (!props.search) return props.children?.map((child) => child[props.itemValue]);
let options = props.children || [];
return props.children
?.filter(
if (props.search) {
options = options.filter(
(child) =>
child[props.itemText].toLowerCase().includes(props.search.toLowerCase()) ||
childrenHaveMatch(child.children)
)
?.map((child) => child[props.itemValue]);
childrenHaveSearchMatch(child[props.itemChildren])
);
}
function childrenHaveMatch(children: Record<string, any>[] | undefined): boolean {
if (props.showSelectionOnly) {
options = options.filter(
(child) =>
props.modelValue.includes(child[props.itemValue]) || childrenHaveValueMatch(child[props.itemChildren])
);
}
return options.map((child) => child[props.itemValue]);
function childrenHaveSearchMatch(children: Record<string, any>[] | undefined): boolean {
if (!children) return false;
return children.some(
(child) =>
child[props.itemText].toLowerCase().includes(props.search.toLowerCase()) ||
childrenHaveMatch(child[props.itemChildren])
childrenHaveSearchMatch(child[props.itemChildren])
);
}
function childrenHaveValueMatch(children: Record<string, any>[] | undefined): boolean {
if (!children) return false;
return children.some(
(child) =>
props.modelValue.includes(child[props.itemValue]) || childrenHaveValueMatch(child[props.itemChildren])
);
}
});
const groupShown = computed(() => {
if (props.showSelectionOnly === true && props.modelValue.includes(props.value)) {
return true;
}
return visibleChildrenValues.value.length > 0;
});
const childrenValues = computed(() => props.children?.map((child) => child[props.itemValue]) || []);
@@ -216,6 +246,7 @@ export default defineComponent({
treeValue,
groupIndeterminateState,
visibleChildrenValues,
groupShown,
};
function emitAll(rawValue: (string | number)[], { added, removed }: Delta) {

View File

@@ -13,6 +13,7 @@
:value="choice[itemValue]"
:children="choice[itemChildren]"
:disabled="disabled"
:show-selection-only="showSelectionOnly"
/>
</v-list>
</template>
@@ -57,6 +58,10 @@ export default defineComponent({
type: Boolean,
default: false,
},
showSelectionOnly: {
type: Boolean,
default: false,
},
},
emits: ['update:modelValue'],
setup(props, { emit }) {

View File

@@ -18,8 +18,19 @@
:disabled="disabled"
:choices="choices"
:value-combining="valueCombining"
:show-selection-only="showSelectionOnly"
@update:model-value="$emit('input', $event)"
/>
<div class="footer">
<span :class="{ active: showSelectionOnly === false }" @click="showSelectionOnly = false">
{{ t('interfaces.select-multiple-checkbox-tree.show_all') }}
</span>
/
<span :class="{ active: showSelectionOnly === true }" @click="showSelectionOnly = true">
{{ t('interfaces.select-multiple-checkbox-tree.show_selected') }}
</span>
</div>
</div>
</template>
@@ -58,6 +69,8 @@ export default defineComponent({
const { t } = useI18n();
const search = ref('');
const showSelectionOnly = ref(false);
const setSearchDebounced = debounce((val: string) => {
searchDebounced.value = val;
}, 250);
@@ -66,7 +79,7 @@ export default defineComponent({
const searchDebounced = ref('');
return { search, t, searchDebounced };
return { search, t, searchDebounced, showSelectionOnly };
},
});
</script>
@@ -90,4 +103,31 @@ export default defineComponent({
.search .v-input {
box-shadow: 0 0 4px 4px var(--background-page);
}
.footer {
position: sticky;
right: 0;
bottom: 0;
z-index: 2;
float: right;
width: max-content;
padding: 4px 8px;
text-align: right;
background-color: var(--background-page);
border-top-left-radius: var(--border-radius);
}
.footer > span {
color: var(--foreground-subdued);
cursor: pointer;
transition: color var(--fast) var(--transition);
}
.footer > span:hover {
color: var(--foreground-normal);
}
.footer > span.active {
color: var(--primary);
}
</style>

View File

@@ -938,6 +938,8 @@ interfaces:
description: Choose between multiple options via nested checkboxes
value_combining: Value Combining
value_combining_note: Controls what value is stored when nested selections are made.
show_all: Show All
show_selected: Show Selected
input-code:
code: Code
description: Write or share code snippets